mapping data to etcd

This commit is contained in:
richardxz
2018-06-16 11:38:37 +08:00
parent 663a17f230
commit b72e332aff
627 changed files with 26684 additions and 26115 deletions

View File

@@ -0,0 +1,140 @@
/*
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"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/rbac/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
)
func (ctl *ClusterRoleCtl) generateObjec(item v1.ClusterRole) *ClusterRole {
name := item.Name
if strings.HasPrefix(name, "system:") {
return nil
}
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
annotation, _ := json.Marshal(item.Annotations)
object := &ClusterRole{Name: name, CreateTime: createTime, AnnotationStr: string(annotation)}
return object
}
func (ctl *ClusterRoleCtl) listAndWatch() {
defer func() {
close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&ClusterRole{}) {
db.DropTable(&ClusterRole{})
}
db = db.CreateTable(&ClusterRole{})
k8sClient := ctl.K8sClient
clusterRoleList, err := k8sClient.RbacV1().ClusterRoles().List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range clusterRoleList.Items {
obj := ctl.generateObjec(item)
if obj != nil {
db.Create(obj)
}
}
clusterRoleWatcher, err := k8sClient.RbacV1().ClusterRoles().Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-clusterRoleWatcher.ResultChan():
var role ClusterRole
if event.Object == nil {
break
}
object := event.Object.(*v1.ClusterRole)
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, "\"\"").Find(&role)
db.Delete(role)
break
}
obj := ctl.generateObjec(*object)
if obj != nil {
db.Save(obj)
}
}
}
}
func (ctl *ClusterRoleCtl) CountWithConditions(conditions string) int {
var object ClusterRole
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *ClusterRoleCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var object ClusterRole
var list []ClusterRole
var total int
order := "createTime desc"
db := ctl.DB
listWithConditions(db, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
return total, list, nil
}
func (ctl *ClusterRoleCtl) Count(namespace string) int {
var count int
db := ctl.DB
db.Model(&ClusterRole{}).Count(&count)
return count
}

View File

@@ -0,0 +1,161 @@
/*
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"
"time"
"github.com/golang/glog"
"k8s.io/api/apps/v1beta2"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
func (ctl *DaemonsetCtl) generateObject(item v1beta2.DaemonSet) *Daemonset {
var app string
var status string
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.CurrentNumberScheduled
desirePodNum := item.Status.DesiredNumberScheduled
createTime := item.CreationTimestamp.Time
release := item.ObjectMeta.Labels["release"]
nodeSelector := item.Spec.Template.Spec.NodeSelector
nodeSelectorStr, _ := json.Marshal(nodeSelector)
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
} else {
app = "-"
}
if createTime.IsZero() {
createTime = time.Now()
}
if availablePodNum >= desirePodNum {
status = running
} else {
status = updating
}
annotation, _ := json.Marshal(item.Annotations)
object := &Daemonset{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
App: app, CreateTime: createTime, Status: status, NodeSelector: string(nodeSelectorStr), AnnotationStr: string(annotation)}
return object
}
func (ctl *DaemonsetCtl) listAndWatch() {
defer func() {
close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Daemonset{}) {
db.DropTable(&Daemonset{})
}
db = db.CreateTable(&Daemonset{})
k8sClient := client.NewK8sClient()
deoloyList, err := k8sClient.AppsV1beta2().DaemonSets("").List(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range deoloyList.Items {
obj := ctl.generateObject(item)
db.Create(obj)
}
watcher, err := k8sClient.AppsV1beta2().DaemonSets("").Watch(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var ss Daemonset
if event.Object == nil {
break
}
object := event.Object.(*v1beta2.DaemonSet)
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&ss)
db.Delete(ss)
break
}
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *DaemonsetCtl) CountWithConditions(conditions string) int {
var object Daemonset
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *DaemonsetCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Daemonset
var object Daemonset
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
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
}

View File

@@ -0,0 +1,161 @@
/*
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"
"time"
"github.com/golang/glog"
"k8s.io/api/apps/v1beta2"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
func (ctl *DeploymentCtl) generateObject(item v1beta2.Deployment) *Deployment {
var app string
var status string
var updateTime time.Time
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.AvailableReplicas
desirePodNum := *item.Spec.Replicas
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
} else {
app = "-"
}
for _, conditon := range item.Status.Conditions {
if conditon.Type == "Progressing" {
updateTime = conditon.LastUpdateTime.Time
}
}
if updateTime.IsZero() {
updateTime = time.Now()
}
if item.Annotations["state"] == "stop" {
status = stopping
} else {
if availablePodNum >= desirePodNum {
status = running
} else {
status = updating
}
}
annotation, _ := json.Marshal(item.Annotations)
return &Deployment{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
App: app, UpdateTime: updateTime, Status: status, AnnotationStr: string(annotation)}
}
func (ctl *DeploymentCtl) listAndWatch() {
defer func() {
close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Deployment{}) {
db.DropTable(&Deployment{})
}
db = db.CreateTable(&Deployment{})
k8sClient := client.NewK8sClient()
deoloyList, err := k8sClient.AppsV1beta2().Deployments("").List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range deoloyList.Items {
obj := ctl.generateObject(item)
db.Create(obj)
}
watcher, err := k8sClient.AppsV1beta2().Deployments("").Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var deploy Deployment
if event.Object == nil {
break
}
object := event.Object.(*v1beta2.Deployment)
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&deploy)
db.Delete(deploy)
break
}
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *DeploymentCtl) CountWithConditions(conditions string) int {
var object Deployment
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *DeploymentCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Deployment
var object Deployment
var total int
order := "updateTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
return total, list, nil
}
func (ctl *DeploymentCtl) Count(namespace string) int {
var count int
db := ctl.DB
if len(namespace) == 0 {
db.Model(&Deployment{}).Count(&count)
} else {
db.Model(&Deployment{}).Where("namespace = ?", namespace).Count(&count)
}
return count
}

View File

@@ -0,0 +1,148 @@
/*
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"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/extensions/v1beta1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
func (ctl *IngressCtl) generateObject(item v1beta1.Ingress) *Ingress {
name := item.Name
namespace := item.Namespace
ip := "-"
tls := "-"
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
var ipList []string
for _, lb := range item.Status.LoadBalancer.Ingress {
if len(lb.IP) > 0 {
ipList = append(ipList, lb.IP)
}
}
if len(ipList) > 0 {
ip = strings.Join(ipList, ",")
}
annotation, _ := json.Marshal(item.Annotations)
object := &Ingress{Namespace: namespace, Name: name, TlsTermination: tls, Ip: ip, CreateTime: createTime, AnnotationStr: string(annotation)}
return object
}
func (ctl *IngressCtl) listAndWatch() {
defer func() {
defer close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Ingress{}) {
db.DropTable(&Ingress{})
}
db = db.CreateTable(&Ingress{})
k8sClient := client.NewK8sClient()
list, err := k8sClient.ExtensionsV1beta1().Ingresses("").List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range list.Items {
obj := ctl.generateObject(item)
db.Create(obj)
}
watcher, err := k8sClient.ExtensionsV1beta1().Ingresses("").Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var ing Ingress
if event.Object == nil {
break
}
object := event.Object.(*v1beta1.Ingress)
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&ing)
db.Delete(ing)
break
}
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *IngressCtl) CountWithConditions(conditions string) int {
var object Ingress
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *IngressCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Ingress
var object Ingress
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
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
}

View File

@@ -0,0 +1,310 @@
/*
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"
"io/ioutil"
"net/http"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/options"
)
const (
provider = "kubernetes"
admin = "admin"
normal = "normal"
view = "view"
kubectlNamespace = "kubesphere"
kubectlConfigKey = "config"
)
var adminRules = []rbac.PolicyRule{rbac.PolicyRule{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}
var normalRules = []rbac.PolicyRule{rbac.PolicyRule{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions"}, Resources: []string{"*"}}}
var viewRules = []rbac.PolicyRule{rbac.PolicyRule{Verbs: []string{"list", "get"}, APIGroups: []string{"", "apps", "extensions"}, Resources: []string{"*"}}}
type runTime struct {
RuntimeId string `json:"runtime_id"`
RuntimeUrl string `json:"runtime_url"`
Name string `json:"name"`
Provider string `json:"provider"`
Zone string `json:"zone"`
RuntimeCredential string `json:"runtime_credential"`
}
type DeleteRunTime struct {
RuntimeId []string `json:"runtime_id"`
}
func makeHttpRequest(method, url, data string) ([]byte, error) {
req, err := http.NewRequest(method, url, strings.NewReader(data))
if err != nil {
glog.Error(err)
return nil, err
}
httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
glog.Error(err)
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
glog.Error(string(body))
defer resp.Body.Close()
return body, nil
}
func (ctl *NamespaceCtl) getKubeConfig(user string) (string, error) {
k8sClient := client.NewK8sClient()
configmap, err := k8sClient.CoreV1().ConfigMaps(kubectlNamespace).Get(user, metaV1.GetOptions{})
if err != nil {
glog.Errorln(err)
return "", err
}
return configmap.Data[kubectlConfigKey], nil
}
func (ctl *NamespaceCtl) deleteOpRuntime(item v1.Namespace) {
runtimeId := item.Annotations["openpitrix_runtime"]
if len(runtimeId) == 0 {
return
}
url := options.ServerOptions.GetOpAddress() + "/v1/runtimes"
var deleteRuntime = DeleteRunTime{RuntimeId: []string{runtimeId}}
body, err := json.Marshal(deleteRuntime)
if err != nil {
glog.Error(err)
return
}
// todo: if delete failed, what's to be done?
makeHttpRequest("DELETE", url, string(body))
}
func (ctl *NamespaceCtl) createOpRuntime(namespace, user string) ([]byte, error) {
zone := namespace
name := namespace
kubeConfig, err := ctl.getKubeConfig(user)
if err != nil {
glog.Error(err)
return nil, err
}
url := options.ServerOptions.GetOpAddress() + "/v1/runtimes"
option := runTime{Name: name, Provider: provider, RuntimeCredential: kubeConfig, Zone: zone}
body, err := json.Marshal(option)
if err != nil {
glog.Error(err)
return nil, err
}
return makeHttpRequest("POST", url, string(body))
}
func (ctl *NamespaceCtl) createDefaultRole(ns string) error {
defer func() {
if err := recover(); err != nil {
glog.Error(err)
}
}()
adminRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: ns}, Rules: adminRules}
normalRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: normal, Namespace: ns}, Rules: normalRules}
viewRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: view, Namespace: ns}, Rules: viewRules}
role, _ := ctl.K8sClient.RbacV1().Roles(ns).Get(admin, metaV1.GetOptions{})
if role.Name != admin {
_, err := ctl.K8sClient.RbacV1().Roles(ns).Create(adminRole)
if err != nil {
glog.Error(err)
return err
}
}
role, _ = ctl.K8sClient.RbacV1().Roles(ns).Get(normal, metaV1.GetOptions{})
if role.Name != normal {
_, err := ctl.K8sClient.RbacV1().Roles(ns).Create(normalRole)
if err != nil {
glog.Error(err)
return err
}
}
role, _ = ctl.K8sClient.RbacV1().Roles(ns).Get(view, metaV1.GetOptions{})
if role.Name != view {
_, err := ctl.K8sClient.RbacV1().Roles(ns).Create(viewRole)
if err != nil {
glog.Error(err)
return err
}
}
return nil
}
func (ctl *NamespaceCtl) createRoleAndRuntime(item v1.Namespace) {
user := item.Annotations["creator"]
ns := item.Name
if len(user) > 0 && len(item.Annotations["openpitrix_runtime"]) == 0 {
err := ctl.createDefaultRole(ns)
if err != nil {
return
}
resp, err := ctl.createOpRuntime(ns, user)
if err != nil {
return
}
var runtime runTime
err = json.Unmarshal(resp, &runtime)
if err != nil {
return
}
item.Annotations["openpitrix_runtime"] = runtime.RuntimeId
ctl.K8sClient.CoreV1().Namespaces().Update(&item)
}
}
func (ctl *NamespaceCtl) generateObject(item v1.Namespace) *Namespace {
name := item.Name
createTime := item.CreationTimestamp.Time
status := fmt.Sprintf("%v", item.Status.Phase)
if createTime.IsZero() {
createTime = time.Now()
}
annotation, _ := json.Marshal(item.Annotations)
object := &Namespace{Name: name, CreateTime: createTime, Status: status, AnnotationStr: string(annotation)}
return object
}
func (ctl *NamespaceCtl) listAndWatch() {
defer func() {
defer close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Namespace{}) {
db.DropTable(&Namespace{})
}
db = db.CreateTable(&Namespace{})
k8sClient := client.NewK8sClient()
list, err := k8sClient.CoreV1().Namespaces().List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range list.Items {
obj := ctl.generateObject(item)
db.Create(obj)
ctl.createRoleAndRuntime(item)
}
watcher, err := k8sClient.CoreV1().Namespaces().Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var ns Namespace
if event.Object == nil {
break
}
object := event.Object.(*v1.Namespace)
if event.Type == watch.Deleted {
db.Where("name=?", object.Name).Find(&ns)
db.Delete(ns)
ctl.deleteOpRuntime(*object)
break
}
ctl.createRoleAndRuntime(*object)
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *NamespaceCtl) CountWithConditions(conditions string) int {
var object Namespace
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *NamespaceCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Namespace
var object Namespace
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
return total, list, nil
}
func (ctl *NamespaceCtl) Count(namespace string) int {
var count int
db := ctl.DB
db.Model(&Namespace{}).Count(&count)
return count
}

View File

@@ -0,0 +1,161 @@
/*
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"
"github.com/golang/glog"
"k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
func (ctl *PodCtl) generateObject(item v1.Pod) *Pod {
name := item.Name
namespace := item.Namespace
podIp := item.Status.PodIP
nodeName := item.Spec.NodeName
nodeIp := item.Status.HostIP
status := string(item.Status.Phase)
createTime := item.CreationTimestamp.Time
containerStatus := item.Status.ContainerStatuses
containerSpecs := item.Spec.Containers
var containers []Container
for _, containerSpec := range containerSpecs {
var container Container
container.Name = containerSpec.Name
container.Image = containerSpec.Image
container.Ports = containerSpec.Ports
for _, status := range containerStatus {
if container.Name == status.Name {
container.Ready = status.Ready
}
}
containers = append(containers, container)
}
containerStr, _ := json.Marshal(containers)
annotation, _ := json.Marshal(item.Annotations)
object := &Pod{Namespace: namespace, Name: name, Node: nodeName, PodIp: podIp, Status: status, NodeIp: nodeIp,
CreateTime: createTime, ContainerStr: string(containerStr), AnnotationStr: string(annotation)}
return object
}
func (ctl *PodCtl) listAndWatch() {
defer func() {
defer close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Pod{}) {
db.DropTable(&Pod{})
}
db = db.CreateTable(&Pod{})
k8sClient := client.NewK8sClient()
list, err := k8sClient.CoreV1().Pods("").List(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range list.Items {
obj := ctl.generateObject(item)
db.Create(obj)
}
watcher, err := k8sClient.CoreV1().Pods("").Watch(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var po Pod
if event.Object == nil {
break
}
object := event.Object.(*v1.Pod)
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&po)
db.Delete(po)
break
}
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *PodCtl) CountWithConditions(conditions string) int {
var object Pod
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *PodCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Pod
var object Pod
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
var containers []Container
json.Unmarshal([]byte(item.ContainerStr), &containers)
list[index].Containers = containers
list[index].ContainerStr = ""
annotation := make(Annotation)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
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
}

View File

@@ -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 (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
const creator = "creator"
func (ctl *PvcCtl) generateObject(item *v1.PersistentVolumeClaim) *Pvc {
name := item.Name
namespace := item.Namespace
status := fmt.Sprintf("%s", item.Status.Phase)
createTime := item.CreationTimestamp.Time
capacity := "-"
if createTime.IsZero() {
createTime = time.Now()
}
if storage, exist := item.Status.Capacity["storage"]; exist {
capacity = storage.String()
}
storageClass := "-"
if item.Spec.StorageClassName != nil {
storageClass = *item.Spec.StorageClassName
}
accessModeStr := "-"
var accessModeList []string
for _, accessMode := range item.Status.AccessModes {
accessModeList = append(accessModeList, string(accessMode))
}
accessModeStr = strings.Join(accessModeList, ",")
annotation, _ := json.Marshal(item.Annotations)
object := &Pvc{Namespace: namespace, Name: name, Status: status, Capacity: capacity,
AccessMode: accessModeStr, StorageClassName: storageClass, CreateTime: createTime, AnnotationStr: string(annotation)}
return object
}
func (ctl *PvcCtl) listAndWatch() {
defer func() {
defer close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Pvc{}) {
db.DropTable(&Pvc{})
}
db = db.CreateTable(&Pvc{})
k8sClient := client.NewK8sClient()
pvcList, err := k8sClient.CoreV1().PersistentVolumeClaims("").List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range pvcList.Items {
obj := ctl.generateObject(&item)
db.Create(obj)
}
watcher, err := k8sClient.CoreV1().PersistentVolumeClaims("").Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var pvc Pvc
if event.Object == nil {
break
}
object := event.Object.(*v1.PersistentVolumeClaim)
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&pvc)
db.Delete(pvc)
break
}
obj := ctl.generateObject(object)
db.Save(obj)
}
}
}
func (ctl *PvcCtl) CountWithConditions(conditions string) int {
var object Pvc
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *PvcCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Pvc
var object Pvc
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
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
}

View File

@@ -0,0 +1,142 @@
/*
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"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/rbac/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
func (ctl *RoleCtl) generateObject(item v1.Role) *Role {
name := item.Name
if strings.HasPrefix(name, "system:") {
return nil
}
namespace := item.Namespace
createTime := item.CreationTimestamp.Time
if createTime.IsZero() {
createTime = time.Now()
}
annotation, _ := json.Marshal(item.Annotations)
object := &Role{Namespace: namespace, Name: name, CreateTime: createTime, AnnotationStr: string(annotation)}
return object
}
func (ctl *RoleCtl) listAndWatch() {
defer func() {
close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Role{}) {
db.DropTable(&Role{})
}
db = db.CreateTable(&Role{})
k8sClient := client.NewK8sClient()
roleList, err := k8sClient.RbacV1().Roles("").List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range roleList.Items {
obj := ctl.generateObject(item)
if obj != nil {
db.Create(obj)
}
}
roleWatcher, err := k8sClient.RbacV1().Roles("").Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-roleWatcher.ResultChan():
var role Role
object := event.Object.(*v1.Role)
if event.Object == nil {
break
}
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&role)
db.Delete(role)
break
}
obj := ctl.generateObject(*object)
if obj != nil {
db.Save(obj)
}
break
}
}
}
func (ctl *RoleCtl) CountWithConditions(conditions string) int {
var object Role
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *RoleCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Role
var object Role
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
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
}

View File

@@ -0,0 +1,100 @@
/*
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"
"github.com/jinzhu/gorm"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/client"
)
type resourceControllers struct {
controllers map[string]Controller
db *gorm.DB
k8sClient *kubernetes.Clientset
}
var stopChan chan struct{}
func (rec *resourceControllers) runContoller(name string) {
var ctl Controller
attr := CommonAttribute{DB: rec.db, K8sClient: rec.k8sClient, stopChan: stopChan, aliveChan: make(chan struct{})}
switch name {
case Deployments:
ctl = &DeploymentCtl{attr}
case Statefulsets:
ctl = &StatefulsetCtl{attr}
case Daemonsets:
ctl = &DaemonsetCtl{attr}
case Ingresses:
ctl = &IngressCtl{attr}
case PersistentVolumeClaim:
ctl = &PvcCtl{attr}
case Roles:
ctl = &RoleCtl{attr}
case ClusterRoles:
ctl = &ClusterRoleCtl{attr}
case Services:
ctl = &ServiceCtl{attr}
case Pods:
ctl = &PodCtl{attr}
case Namespaces:
ctl = &NamespaceCtl{attr}
case StorageClasses:
ctl = &StorageClassCtl{attr}
default:
return
}
rec.controllers[name] = ctl
go ctl.listAndWatch()
}
func Run() {
db := client.NewDBClient()
stopChan := make(chan struct{})
defer db.Commit()
defer db.Close()
defer close(stopChan)
rec := resourceControllers{k8sClient: client.NewK8sClient(), db: db, controllers: make(map[string]Controller)}
for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services,
Ingresses, Roles, ClusterRoles, Namespaces, StorageClasses} {
rec.runContoller(item)
}
for {
for ctlName, controller := range rec.controllers {
select {
case _, isClose := <-controller.chanAlive():
if !isClose {
glog.Errorf("controller %s have stopped, restart it", ctlName)
rec.runContoller(ctlName)
}
default:
time.Sleep(5 * time.Second)
}
}
}
}

View File

@@ -0,0 +1,218 @@
/*
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"
"strings"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
const (
headlessSelector = "Headless(Selector)"
headlessExternal = "Headless(ExternalName)"
virtualIp = "Virtual IP"
)
func (ctl *ServiceCtl) loadBalancerStatusStringer(item v1.Service) string {
ingress := item.Status.LoadBalancer.Ingress
result := sets.NewString()
for i := range ingress {
if ingress[i].IP != "" {
result.Insert(ingress[i].IP)
} else if ingress[i].Hostname != "" {
result.Insert(ingress[i].Hostname)
}
}
r := strings.Join(result.List(), ",")
return r
}
func (ctl *ServiceCtl) getExternalIp(item v1.Service) string {
switch item.Spec.Type {
case "ClusterIP", "NodePort":
if len(item.Spec.ExternalIPs) > 0 {
return strings.Join(item.Spec.ExternalIPs, ",")
}
case "ExternalName":
return item.Spec.ExternalName
case "LoadBalancer":
lbIps := ctl.loadBalancerStatusStringer(item)
if len(item.Spec.ExternalIPs) > 0 {
results := []string{}
if len(lbIps) > 0 {
results = append(results, strings.Split(lbIps, ",")...)
}
results = append(results, item.Spec.ExternalIPs...)
return strings.Join(results, ",")
}
if len(lbIps) > 0 {
return lbIps
}
return "<pending>"
}
return "-"
}
func (ctl *ServiceCtl) generateObject(item v1.Service) *Service {
name := item.Name
namespace := item.Namespace
createTime := item.CreationTimestamp.Time
externalIp := ctl.getExternalIp(item)
serviceType := virtualIp
vip := item.Spec.ClusterIP
ports := ""
if createTime.IsZero() {
createTime = time.Now()
}
if item.Spec.ClusterIP == "None" {
serviceType = headlessSelector
vip = "-"
}
if len(item.Spec.ExternalName) > 0 {
serviceType = headlessExternal
vip = "-"
}
if len(item.Spec.ExternalIPs) > 0 {
externalIp = strings.Join(item.Spec.ExternalIPs, ",")
}
for _, portItem := range item.Spec.Ports {
port := portItem.Port
targetPort := portItem.TargetPort.String()
protocol := portItem.Protocol
ports += fmt.Sprintf("%d:%s/%s,", port, targetPort, protocol)
}
if len(ports) == 0 {
ports = "-"
} else {
ports = ports[0 : len(ports)-1]
}
annotation, _ := json.Marshal(item.Annotations)
object := &Service{Namespace: namespace, Name: name, ServiceType: serviceType, ExternalIp: externalIp,
VirtualIp: vip, CreateTime: createTime, Ports: ports, AnnotationStr: string(annotation)}
return object
}
func (ctl *ServiceCtl) listAndWatch() {
defer func() {
defer close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Service{}) {
db.DropTable(&Service{})
}
db = db.CreateTable(&Service{})
k8sClient := client.NewK8sClient()
svcList, err := k8sClient.CoreV1().Services("").List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range svcList.Items {
obj := ctl.generateObject(item)
db.Create(obj)
}
watcher, err := k8sClient.CoreV1().Services("").Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var svc Service
object := event.Object.(*v1.Service)
if event.Object == nil {
break
}
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&svc)
db.Delete(svc)
break
}
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *ServiceCtl) CountWithConditions(conditions string) int {
var object Service
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *ServiceCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Service
var object Service
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
return total, list, nil
}
func (ctl *ServiceCtl) Count(namespace string) int {
var count int
db := ctl.DB
if len(namespace) == 0 {
db.Model(&Service{}).Count(&count)
} else {
db.Model(&Service{}).Where("namespace = ?", namespace).Count(&count)
}
return count
}

View File

@@ -0,0 +1,156 @@
/*
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"
"time"
"github.com/golang/glog"
"k8s.io/api/apps/v1beta2"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
func (ctl *StatefulsetCtl) generateObject(item v1beta2.StatefulSet) *Statefulset {
var app string
var status string
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.ReadyReplicas
desirePodNum := *item.Spec.Replicas
createTime := item.CreationTimestamp.Time
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if createTime.IsZero() {
createTime = time.Now()
}
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
} else {
app = "-"
}
if item.Annotations["state"] == "stop" {
status = stopping
} else {
if availablePodNum >= desirePodNum {
status = running
} else {
status = updating
}
}
annotation, _ := json.Marshal(item.Annotations)
statefulSetObject := &Statefulset{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
App: app, CreateTime: createTime, Status: status, AnnotationStr: string(annotation)}
return statefulSetObject
}
func (ctl *StatefulsetCtl) listAndWatch() {
defer func() {
defer close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&Statefulset{}) {
db.DropTable(&Statefulset{})
}
db = db.CreateTable(&Statefulset{})
k8sClient := client.NewK8sClient()
deoloyList, err := k8sClient.AppsV1beta2().StatefulSets("").List(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
}
for _, item := range deoloyList.Items {
obj := ctl.generateObject(item)
db.Create(obj)
}
watcher, err := k8sClient.AppsV1beta2().StatefulSets("").Watch(metaV1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var tmp Statefulset
if event.Object == nil {
break
}
object := event.Object.(*v1beta2.StatefulSet)
if event.Type == watch.Deleted {
db.Where("name=? And namespace=?", object.Name, object.Namespace).Find(&tmp)
db.Delete(tmp)
break
}
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *StatefulsetCtl) CountWithConditions(conditions string) int {
var object Statefulset
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *StatefulsetCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []Statefulset
var object Statefulset
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, item := range list {
annotation := make(map[string]string)
json.Unmarshal([]byte(item.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
}
return total, list, nil
}
func (ctl *StatefulsetCtl) Count(namespace string) int {
var count int
db := ctl.DB
if len(namespace) == 0 {
db.Model(&Statefulset{}).Count(&count)
} else {
db.Model(&Statefulset{}).Where("namespace = ?", namespace).Count(&count)
}
return count
}

View File

@@ -0,0 +1,141 @@
/*
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/storage/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"kubesphere.io/kubesphere/pkg/client"
)
func (ctl *StorageClassCtl) generateObject(item v1beta1.StorageClass) *StorageClass {
name := item.Name
createTime := item.CreationTimestamp.Time
isDefault := false
if item.Annotations["storageclass.beta.kubernetes.io/is-default-class"] == "true" {
isDefault = true
}
if createTime.IsZero() {
createTime = time.Now()
}
annotation, _ := json.Marshal(item.Annotations)
object := &StorageClass{Name: name, CreateTime: createTime, IsDefault: isDefault, AnnotationStr: string(annotation)}
return object
}
func (ctl *StorageClassCtl) listAndWatch() {
defer func() {
defer close(ctl.aliveChan)
if err := recover(); err != nil {
glog.Error(err)
return
}
}()
db := ctl.DB
if db.HasTable(&StorageClass{}) {
db.DropTable(&StorageClass{})
}
db = db.CreateTable(&StorageClass{})
k8sClient := client.NewK8sClient()
list, err := k8sClient.StorageV1beta1().StorageClasses().List(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, item := range list.Items {
obj := ctl.generateObject(item)
db.Create(obj)
}
watcher, err := k8sClient.StorageV1beta1().StorageClasses().Watch(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-ctl.stopChan:
return
case event := <-watcher.ResultChan():
var sc StorageClass
if event.Object == nil {
break
}
object := event.Object.(*v1beta1.StorageClass)
if event.Type == watch.Deleted {
db.Where("name=?", object.Name).Find(&sc)
db.Delete(sc)
break
}
obj := ctl.generateObject(*object)
db.Save(obj)
}
}
}
func (ctl *StorageClassCtl) CountWithConditions(conditions string) int {
var object StorageClass
return countWithConditions(ctl.DB, conditions, &object)
}
func (ctl *StorageClassCtl) ListWithConditions(conditions string, paging *Paging) (int, interface{}, error) {
var list []StorageClass
var object StorageClass
var total int
order := "createTime desc"
listWithConditions(ctl.DB, &total, &object, &list, conditions, paging, order)
for index, storageClass := range list {
name := storageClass.Name
annotation := make(map[string]string)
json.Unmarshal([]byte(storageClass.AnnotationStr), &annotation)
list[index].Annotation = annotation
list[index].AnnotationStr = ""
pvcCtl := PvcCtl{CommonAttribute{K8sClient: ctl.K8sClient, DB: ctl.DB}}
list[index].Count = pvcCtl.CountWithConditions(fmt.Sprintf("storage_class=\"%s\"", name))
}
return total, list, nil
}
func (ctl *StorageClassCtl) Count(name string) int {
var count int
db := ctl.DB
db.Model(&StorageClass{}).Count(&count)
return count
}

View File

@@ -0,0 +1,361 @@
/*
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/jinzhu/gorm"
"k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
)
const (
stopping = "stopped"
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"
Pods = "pods"
Deployments = "deployments"
Daemonsets = "daemonsets"
Statefulsets = "statefulsets"
Namespaces = "namespaces"
Ingresses = "ingresses"
PersistentVolumeClaim = "persistent-volume-claims"
Roles = "roles"
ClusterRoles = "cluster-roles"
Services = "services"
StorageClasses = "storage-classes"
)
var ResourceTable = map[string]string{Deployments: tableDeployments, Statefulsets: tableStatefulsets, Daemonsets: tableDaemonsets,
Pods: tablePods, Namespaces: tableNamespaces, Ingresses: tableIngresses, PersistentVolumeClaim: tablePersistentVolumeClaim, Roles: tableRoles,
Services: tableServices, StorageClasses: tableStorageClasses, ClusterRoles: tableClusterRoles}
type Annotation map[string]string
//
//func (annotation *Annotation)Scan(val interface{}) error{
// switch val := val.(type){
// case string:
// return json.Unmarshal([]byte(val), annotation)
// case []byte:
// return json.Unmarshal(val, annotation)
// default:
// return errors.New("not support")
// }
// return nil
//}
//
//func (annotation *Annotation)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"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
UpdateTime time.Time `gorm:"column:updateTime" json:"updateTime,omitempty"`
}
func (Deployment) TableName() string {
return tableDeployments
}
type Statefulset struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
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"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Statefulset) TableName() string {
return tableStatefulsets
}
type Daemonset struct {
Name string `gorm:"primary_key" json:"name,omitempty"`
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"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Daemonset) TableName() string {
return tableDaemonsets
}
type Service struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
ServiceType string `json:"type,omitempty"`
VirtualIp string `json:"virtualIp,omitempty"`
ExternalIp string `json:"externalIp,omitempty"`
Ports string `json:"ports,omitempty"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Service) TableName() string {
return tableServices
}
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"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
StorageClassName string `gorm:"column:storage_class" json:"storage_class,omitempty"`
}
func (Pvc) TableName() string {
return tablePersistentVolumeClaim
}
type Ingress struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
Ip string `json:"ip,omitempty"`
TlsTermination string `json:"tlsTermination,omitempty"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Ingress) TableName() string {
return tableIngresses
}
type Pod struct {
Name string `gorm:"primary_key" json:"name"`
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"`
ContainerStr string `gorm:"type:text" json:",omitempty"`
Containers []Container `json:"containers,omitempty"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
type Container struct {
Name string `json:"name"`
Ready bool `json:"ready,omitempty"`
Image string `json:"image"`
Ports []v1.ContainerPort `json:"ports"`
}
func (Pod) TableName() string {
return tablePods
}
type Role struct {
Name string `gorm:"primary_key" json:"name"`
Namespace string `gorm:"primary_key" json:"namespace"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Role) TableName() string {
return tableRoles
}
type ClusterRole struct {
Name string `gorm:"primary_key" json:"name"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (ClusterRole) TableName() string {
return tableClusterRoles
}
type Namespace struct {
Name string `gorm:"primary_key" json:"name"`
Creator string `json:"creator,omitempty"`
Status string `json:"status"`
Descrition string `json:"description,omitempty"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
}
func (Namespace) TableName() string {
return tableNamespaces
}
type StorageClass struct {
Name string `gorm:"primary_key" json:"name"`
Creator string `json:"creator,omitempty"`
AnnotationStr string `gorm:"type:text" json:"annotationStr,omitempty"`
Annotation Annotation `gorm:"-" json:"annotation"`
CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"`
IsDefault bool `json:"default"`
Count int `json:"count"`
}
func (StorageClass) TableName() string {
return tableStorageClasses
}
type Paging struct {
Limit, Offset int
}
type Controller interface {
listAndWatch()
chanStop() chan struct{}
chanAlive() chan struct{}
Count(conditions string) int
ListWithConditions(condition string, paging *Paging) (int, interface{}, error)
}
type CommonAttribute struct {
K8sClient *kubernetes.Clientset
DB *gorm.DB
stopChan chan struct{}
aliveChan chan struct{}
}
func (ca *CommonAttribute) chanStop() chan struct{} {
return ca.stopChan
}
func (ca *CommonAttribute) chanAlive() chan struct{} {
return ca.aliveChan
}
type DeploymentCtl struct {
CommonAttribute
}
type StatefulsetCtl struct {
CommonAttribute
}
type DaemonsetCtl struct {
CommonAttribute
}
type ServiceCtl struct {
CommonAttribute
}
type PvcCtl struct {
CommonAttribute
}
type PodCtl struct {
CommonAttribute
}
type IngressCtl struct {
CommonAttribute
}
type NamespaceCtl struct {
CommonAttribute
}
type StorageClassCtl struct {
CommonAttribute
}
type RoleCtl struct {
CommonAttribute
}
type ClusterRoleCtl struct {
CommonAttribute
}
func listWithConditions(db *gorm.DB, total *int, object, list interface{}, conditions string, paging *Paging, order string) {
if len(conditions) == 0 {
db.Model(object).Count(total)
} else {
db.Model(object).Where(conditions).Count(total)
}
if paging != nil {
if len(conditions) > 0 {
db.Where(conditions).Order(order).Limit(paging.Limit).Offset(paging.Offset).Find(list)
} else {
db.Order(order).Limit(paging.Limit).Offset(paging.Offset).Find(list)
}
} else {
if len(conditions) > 0 {
db.Where(conditions).Order(order).Find(list)
} else {
db.Order(order).Find(list)
}
}
}
func countWithConditions(db *gorm.DB, conditions string, object interface{}) int {
var count int
if len(conditions) == 0 {
db.Model(object).Count(&count)
} else {
db.Model(object).Where(conditions).Count(&count)
}
return count
}

View File

@@ -1,231 +0,0 @@
/*
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 cronjobs
import (
"encoding/json"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/jobs/resources"
)
const (
pods = "count/pods"
daemonsets = "count/daemonsets.apps"
deployments = "count/deployments.apps"
ingress = "count/ingresses.extensions"
roles = "count/roles.rbac.authorization.k8s.io"
services = "count/services"
statefulsets = "count/statefulsets.apps"
persistentvolumeclaims = "persistentvolumeclaims"
)
type resourceUsage struct {
NameSpace string
Data v1.ResourceQuotaStatus
UpdateTimeStamp int64
}
type resourceQuotaWorker struct {
k8sClient *kubernetes.Clientset
resChan chan dataType
stopChan chan struct{}
}
func (ru resourceUsage) namespace() string {
return ru.NameSpace
}
type workloadList map[string][]resources.WorkLoadObject
type otherResourceList map[string][]resources.OtherResourceObject
type workload struct {
ResourceType string `json:"type"`
ResourceList workloadList `json:"lists"`
UpdateTimeStamp int64 `json:"updateTimestamp"`
}
type otherResource struct {
ResourceType string `json:"type"`
ResourceList otherResourceList `json:"lists"`
UpdateTimeStamp int64 `json:"updateTimestamp"`
}
var workLoads = []string{"deployments", "daemonsets", "statefulsets"}
var resourceMap = map[string]string{daemonsets: "daemonsets", deployments: "deployments", ingress: "ingresses",
roles: "roles", services: "services", statefulsets: "statefulsets", persistentvolumeclaims: "persistent-volume-claim", pods: "pods"}
func contain(items []string, item string) bool {
for _, v := range items {
if v == item {
return false
}
}
return true
}
func (rw *resourceQuotaWorker) getResourceusage(namespace, resourceName string) (int, error) {
etcdcli, err := client.NewEtcdClient()
if err != nil {
glog.Error(err)
return 0, err
}
defer etcdcli.Close()
key := constants.Root + "/" + resourceName
value, err := etcdcli.Get(key)
if err != nil {
glog.Error(err)
}
if contain(workLoads, resourceName) {
resourceStatus := workload{ResourceList: make(workloadList)}
err := json.Unmarshal(value, &resourceStatus)
if err != nil {
glog.Error(err)
return 0, nil
}
return len(resourceStatus.ResourceList[namespace]), nil
} else {
resourceStatus := otherResource{ResourceList: make(otherResourceList)}
err := json.Unmarshal(value, &resourceStatus)
if err != nil {
glog.Error(err)
return 0, err
}
return len(resourceStatus.ResourceList[namespace]), nil
}
return 0, nil
}
func (rw *resourceQuotaWorker) updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
if tmpResourceList == nil {
tmpResourceList = resourceList
}
for resource, usage := range resourceList {
tmpUsage, exist := tmpResourceList[resource]
if !exist {
tmpResourceList[resource] = usage
}
if tmpUsage.Cmp(usage) == 1 {
tmpResourceList[resource] = usage
}
}
}
func (rw *resourceQuotaWorker) getNamespaceResourceUsageByQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
quotaList, err := rw.k8sClient.CoreV1().ResourceQuotas(namespace).List(meta_v1.ListOptions{})
if err != nil || len(quotaList.Items) == 0 {
return nil, err
}
quotaStatus := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
for _, quota := range quotaList.Items {
rw.updateNamespaceQuota(quotaStatus.Hard, quota.Status.Hard)
rw.updateNamespaceQuota(quotaStatus.Used, quota.Status.Used)
}
return &quotaStatus, nil
}
func (rw *resourceQuotaWorker) getNamespaceQuota(namespace string) (v1.ResourceQuotaStatus, error) {
quota, err := rw.getNamespaceResourceUsageByQuota(namespace)
if err != nil {
return v1.ResourceQuotaStatus{}, err
}
if quota == nil {
quota = new(v1.ResourceQuotaStatus)
quota.Used = make(v1.ResourceList)
}
for k, v := range resourceMap {
if _, exist := quota.Used[v1.ResourceName(k)]; !exist {
used, err := rw.getResourceusage(namespace, v)
if err != nil {
continue
}
var quantity resource.Quantity
quantity.Set(int64(used))
quota.Used[v1.ResourceName(k)] = quantity
}
}
return *quota, nil
}
func (rw *resourceQuotaWorker) workOnce() {
clusterQuota := new(v1.ResourceQuotaStatus)
clusterQuota.Used = make(v1.ResourceList)
namespaces, err := rw.k8sClient.CoreV1().Namespaces().List(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
return
}
for _, ns := range namespaces.Items {
namespace := ns.Name
nsquota, err := rw.getNamespaceQuota(namespace)
if err != nil {
glog.Error(err)
return
}
res := resourceUsage{NameSpace: namespace, Data: nsquota, UpdateTimeStamp: time.Now().Unix()}
rw.resChan <- res
for k, v := range nsquota.Used {
tmp := clusterQuota.Used[k]
tmp.Add(v)
clusterQuota.Used[k] = tmp
}
}
var quantity resource.Quantity
quantity.Set(int64(len(namespaces.Items)))
clusterQuota.Used["count/namespaces"] = quantity
res := resourceUsage{NameSpace: "\"\"", Data: *clusterQuota, UpdateTimeStamp: time.Now().Unix()}
rw.resChan <- res
}
func (rw *resourceQuotaWorker) chanStop() chan struct{} {
return rw.stopChan
}
func (rw *resourceQuotaWorker) chanRes() chan dataType {
return rw.resChan
}

View File

@@ -1,136 +0,0 @@
/*
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 cronjobs
import (
"encoding/json"
"time"
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
)
var etcdClient *client.EtcdClient
var stopChan = make(chan struct{})
type dataType interface {
namespace() string
}
type Worker interface {
workOnce()
chanRes() chan dataType
chanStop() chan struct{}
}
func registerWorker(workers map[string]Worker, name string) {
glog.Infof("Register cronjob: %s", name)
k8sClient := client.NewK8sClient()
switch name {
case constants.WorkloadStatusKey:
worker := workloadWorker{k8sClient: k8sClient, stopChan: stopChan, resChan: make(chan dataType, 10)}
workers[constants.WorkloadStatusKey] = &worker
case constants.QuotaKey:
worker := resourceQuotaWorker{k8sClient: k8sClient, stopChan: stopChan, resChan: make(chan dataType, 10)}
workers[constants.QuotaKey] = &worker
}
}
func run(worker Worker) {
defer func() {
if err := recover(); err != nil {
glog.Error(err)
close(worker.chanRes())
}
}()
for {
select {
case <-worker.chanStop():
return
default:
break
}
worker.workOnce()
time.Sleep(time.Duration(constants.UpdateCircle) * time.Second)
}
}
func startWorks(workers map[string]Worker) {
for wokername, woker := range workers {
glog.Infof("cronjob %s start to work", wokername)
go run(woker)
}
}
func receiveResourceStatus(workers map[string]Worker) {
defer func() {
close(stopChan)
}()
for {
for name, worker := range workers {
select {
case res, ok := <-worker.chanRes():
if !ok {
glog.Errorf("cronjob:%s have stopped", name)
registerWorker(workers, name)
run(workers[name])
} else {
value, err := json.Marshal(res)
if err != nil {
glog.Error(err)
continue
}
key := constants.Root + "/" + name + "/" + res.namespace()
err = etcdClient.Put(key, string(value))
if err != nil {
glog.Error(err)
}
}
default:
continue
}
}
}
}
func Run() {
glog.Info("Begin to run cronjob")
var err error
etcdClient, err = client.NewEtcdClient()
if err != nil {
glog.Error(err)
}
defer etcdClient.Close()
workers := make(map[string]Worker)
workerList := []string{constants.QuotaKey, constants.WorkloadStatusKey}
for _, name := range workerList {
registerWorker(workers, name)
}
startWorks(workers)
receiveResourceStatus(workers)
}

View File

@@ -1,104 +0,0 @@
package cronjobs
import (
"encoding/json"
"time"
"github.com/golang/glog"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
)
var workLoadList = []string{"deployments", "daemonsets", "statefulsets"}
type workLoadStatus struct {
NameSpace string
Data map[string]int
UpdateTimeStamp int64
}
func (ws workLoadStatus) namespace() string {
return ws.NameSpace
}
type workloadWorker struct {
k8sClient *kubernetes.Clientset
resChan chan dataType
stopChan chan struct{}
}
func (ww *workloadWorker) GetNamespacesResourceStatus(namespace string) (map[string]int, error) {
cli, err := client.NewEtcdClient()
if err != nil {
glog.Error(err)
return nil, err
}
defer cli.Close()
res := make(map[string]int)
for _, resourceName := range workLoadList {
key := constants.Root + "/" + resourceName
value, err := cli.Get(key)
if err != nil {
continue
}
resourceStatus := workload{ResourceList: make(workloadList)}
err = json.Unmarshal(value, &resourceStatus)
if err != nil {
glog.Error(err)
return nil, err
}
notReady := 0
for _, v := range resourceStatus.ResourceList[namespace] {
if !v.Ready {
notReady++
}
}
res[resourceName] = notReady
}
return res, nil
}
func (ww workloadWorker) workOnce() {
namespaces, err := ww.k8sClient.CoreV1().Namespaces().List(meta_v1.ListOptions{})
if err != nil {
glog.Error(err)
}
resourceStatus := make(map[string]int)
for _, item := range namespaces.Items {
namespace := item.Name
namespacesResourceStatus, err := ww.GetNamespacesResourceStatus(namespace)
if err != nil {
glog.Error(err)
}
var ws = workLoadStatus{UpdateTimeStamp: time.Now().Unix(), Data: namespacesResourceStatus, NameSpace: namespace}
ww.resChan <- ws
for k, v := range namespacesResourceStatus {
resourceStatus[k] = v + resourceStatus[k]
}
}
var ws = workLoadStatus{UpdateTimeStamp: time.Now().Unix(), Data: resourceStatus, NameSpace: "\"\""}
ww.resChan <- ws
}
func (ww workloadWorker) chanRes() chan dataType {
return ww.resChan
}
func (ww workloadWorker) chanStop() chan struct{} {
return ww.stopChan
}

View File

@@ -1,108 +0,0 @@
/*
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 resources
import (
"k8s.io/api/apps/v1beta2"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type daemonset struct {
k8sClient *kubernetes.Clientset
}
func (ds *daemonset) list() (interface{}, error) {
daemonsetList, err := ds.k8sClient.AppsV1beta2().DaemonSets("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return daemonsetList.Items, nil
}
func (ds *daemonset) getWatcher() (watch.Interface, error) {
watcher, err := ds.k8sClient.AppsV1beta2().DaemonSets("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (ds *daemonset) generateObject(item v1beta2.DaemonSet) WorkLoadObject {
var app string
var ready bool
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.CurrentNumberScheduled
desirePodNum := item.Status.DesiredNumberScheduled
createTime := item.CreationTimestamp
release := item.ObjectMeta.Labels["release"]
nodeSelector := item.Spec.Template.Spec.NodeSelector
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
} else {
app = "-"
}
if availablePodNum >= desirePodNum {
ready = true
} else {
ready = false
}
workloadObject := WorkLoadObject{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
App: app, CreateTime: createTime, Ready: ready, NodeSelector: nodeSelector}
return workloadObject
}
func (ds *daemonset) updateWithObject(status *ResourceStatus, item v1beta2.DaemonSet) {
namespace := item.Namespace
dsObject := ds.generateObject(item)
status.ResourceList.update(namespace, dsObject)
}
func (ds *daemonset) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1beta2.DaemonSet)
for _, item := range items {
ds.updateWithObject(status, item)
}
}
func (ds *daemonset) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1beta2.DaemonSet)
namespace := object.Namespace
daemonsetObject := ds.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, daemonsetObject)
return
}
ds.updateWithObject(status, *object)
}

View File

@@ -1,113 +0,0 @@
/*
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 resources
import (
"k8s.io/api/apps/v1beta2"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type deployment struct {
k8sClient *kubernetes.Clientset
}
func (deploy *deployment) list() (interface{}, error) {
deoloyList, err := deploy.k8sClient.AppsV1beta2().Deployments("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return deoloyList.Items, nil
}
func (deploy *deployment) getWatcher() (watch.Interface, error) {
watcher, err := deploy.k8sClient.AppsV1beta2().Deployments("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (deploy *deployment) generateObject(item v1beta2.Deployment) WorkLoadObject {
var app string
var ready bool
var updateTime meta_v1.Time
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.AvailableReplicas
desirePodNum := *item.Spec.Replicas
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
} else {
app = "-"
}
for _, conditon := range item.Status.Conditions {
if conditon.Type == "Progressing" {
updateTime = conditon.LastUpdateTime
}
}
if availablePodNum >= desirePodNum {
ready = true
} else {
ready = false
}
deployObject := WorkLoadObject{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
App: app, UpdateTime: updateTime, Ready: ready}
return deployObject
}
func (deploy *deployment) updateWithObject(status *ResourceStatus, item v1beta2.Deployment) {
namespace := item.Namespace
deployObject := deploy.generateObject(item)
status.ResourceList.update(namespace, deployObject)
}
func (deploy *deployment) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1beta2.Deployment)
for _, item := range items {
deploy.updateWithObject(status, item)
}
}
func (deploy *deployment) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1beta2.Deployment)
namespace := object.Namespace
deployObject := deploy.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, deployObject)
return
}
deploy.updateWithObject(status, *object)
}

View File

@@ -1,87 +0,0 @@
/*
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 resources
import (
"k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type ingress struct {
k8sClient *kubernetes.Clientset
}
func (ing *ingress) list() (interface{}, error) {
list, err := ing.k8sClient.ExtensionsV1beta1().Ingresses("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return list.Items, nil
}
func (ing *ingress) getWatcher() (watch.Interface, error) {
watcher, err := ing.k8sClient.ExtensionsV1beta1().Ingresses("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (ing *ingress) generateObject(item v1beta1.Ingress) OtherResourceObject {
name := item.Name
ns := item.Namespace
object := OtherResourceObject{Namespace: ns, Name: name}
return object
}
func (ing *ingress) updateWithObject(status *ResourceStatus, item v1beta1.Ingress) {
namespace := item.Namespace
object := ing.generateObject(item)
status.ResourceList.update(namespace, object)
}
func (ing *ingress) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1beta1.Ingress)
for _, item := range items {
ing.updateWithObject(status, item)
}
}
func (ing *ingress) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1beta1.Ingress)
namespace := object.Namespace
tmpObject := ing.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, tmpObject)
return
}
ing.updateWithObject(status, *object)
}

View File

@@ -1,87 +0,0 @@
/*
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 resources
import (
"k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type namespace struct {
k8sClient *kubernetes.Clientset
}
func (ns *namespace) list() (interface{}, error) {
nsList, err := ns.k8sClient.CoreV1().Namespaces().List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return nsList.Items, nil
}
func (ns *namespace) getWatcher() (watch.Interface, error) {
watcher, err := ns.k8sClient.CoreV1().Namespaces().Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (ns *namespace) generateObject(item v1.Namespace) OtherResourceObject {
name := item.Name
nsp := item.Namespace
object := OtherResourceObject{Namespace: nsp, Name: name}
return object
}
func (ns *namespace) updateWithObject(status *ResourceStatus, item v1.Namespace) {
namespace := item.Namespace
object := ns.generateObject(item)
status.ResourceList.update(namespace, object)
}
func (ns *namespace) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1.Namespace)
for _, item := range items {
ns.updateWithObject(status, item)
}
}
func (ns *namespace) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1.Namespace)
namespace := object.Namespace
tmpObject := ns.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, tmpObject)
return
}
ns.updateWithObject(status, *object)
}

View File

@@ -1,87 +0,0 @@
/*
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 resources
import (
"k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type pod struct {
k8sClient *kubernetes.Clientset
}
func (po *pod) list() (interface{}, error) {
list, err := po.k8sClient.CoreV1().Pods("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return list.Items, nil
}
func (po *pod) getWatcher() (watch.Interface, error) {
watcher, err := po.k8sClient.CoreV1().Pods("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (po *pod) generateObject(item v1.Pod) OtherResourceObject {
name := item.Name
ns := item.Namespace
Object := OtherResourceObject{Namespace: ns, Name: name}
return Object
}
func (po *pod) updateWithObject(status *ResourceStatus, item v1.Pod) {
namespace := item.Namespace
object := po.generateObject(item)
status.ResourceList.update(namespace, object)
}
func (po *pod) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1.Pod)
for _, item := range items {
po.updateWithObject(status, item)
}
}
func (po *pod) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1.Pod)
namespace := object.Namespace
tmpObject := po.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, tmpObject)
return
}
po.updateWithObject(status, *object)
}

View File

@@ -1,87 +0,0 @@
/*
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 resources
import (
"k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type persistmentVolume struct {
k8sClient *kubernetes.Clientset
}
func (pvc *persistmentVolume) list() (interface{}, error) {
list, err := pvc.k8sClient.CoreV1().PersistentVolumeClaims("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return list.Items, nil
}
func (pvc *persistmentVolume) getWatcher() (watch.Interface, error) {
watcher, err := pvc.k8sClient.CoreV1().PersistentVolumeClaims("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (pvc *persistmentVolume) generateObject(item v1.PersistentVolumeClaim) OtherResourceObject {
name := item.Name
ns := item.Namespace
object := OtherResourceObject{Namespace: ns, Name: name}
return object
}
func (pvc *persistmentVolume) updateWithObject(status *ResourceStatus, item v1.PersistentVolumeClaim) {
namespace := item.Namespace
object := pvc.generateObject(item)
status.ResourceList.update(namespace, object)
}
func (pvc *persistmentVolume) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1.PersistentVolumeClaim)
for _, item := range items {
pvc.updateWithObject(status, item)
}
}
func (pvc *persistmentVolume) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1.PersistentVolumeClaim)
namespace := object.Namespace
tmpObject := pvc.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, tmpObject)
return
}
pvc.updateWithObject(status, *object)
}

View File

@@ -1,87 +0,0 @@
/*
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 resources
import (
"k8s.io/api/rbac/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type role struct {
k8sClient *kubernetes.Clientset
}
func (r *role) list() (interface{}, error) {
list, err := r.k8sClient.RbacV1().Roles("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return list.Items, nil
}
func (r *role) getWatcher() (watch.Interface, error) {
watcher, err := r.k8sClient.RbacV1().Roles("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (r *role) generateObject(item v1.Role) OtherResourceObject {
name := item.Name
ns := item.Namespace
object := OtherResourceObject{Namespace: ns, Name: name}
return object
}
func (r *role) updateWithObject(status *ResourceStatus, item v1.Role) {
namespace := item.Namespace
object := r.generateObject(item)
status.ResourceList.update(namespace, object)
}
func (r *role) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1.Role)
for _, item := range items {
r.updateWithObject(status, item)
}
}
func (r *role) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1.Role)
namespace := object.Namespace
tmpObject := r.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, tmpObject)
return
}
r.updateWithObject(status, *object)
}

View File

@@ -1,178 +0,0 @@
/*
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 resources
import (
"encoding/json"
"time"
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
)
var etcdClient *client.EtcdClient
var stopChan = make(chan struct{})
const (
pods = "pods"
deployments = "deployments"
daemonsets = "daemonsets"
statefulsets = "statefulsets"
namespaces = "namespaces"
ingresses = "ingresses"
persistentVolumeClaim = "persistent-volume-claim"
roles = "roles"
services = "services"
)
func registerResource(resourceChans map[string]ResourceChan, resourceType string) {
resourceChan := ResourceChan{Type: resourceType, StatusChan: make(chan *ResourceStatus), StopChan: stopChan}
resourceChans[resourceType] = resourceChan
}
func updateStatus(resource Resource, resourceChan ResourceChan) {
defer func() {
if err := recover(); err != nil {
glog.Error(err)
close(resourceChan.StatusChan)
}
}()
var clusterStatus ResourceStatus
clusterStatus.UpdateTimeStamp = time.Now().Unix()
clusterStatus.ResourceType = resourceChan.Type
items, err := resource.list()
if err != nil {
glog.Errorln(err)
return
}
resource.updateWithObjects(&clusterStatus, items)
watcher, err := resource.getWatcher()
if err != nil {
glog.Error(err)
return
}
for {
select {
case <-resourceChan.StopChan:
return
case event := <-watcher.ResultChan():
resource.updateWithEvent(&clusterStatus, event)
break
default:
break
}
if time.Now().Unix()-clusterStatus.UpdateTimeStamp > constants.UpdateCircle {
clusterStatus.UpdateTimeStamp = time.Now().Unix()
resourceChan.StatusChan <- &clusterStatus
}
}
}
func updateResourceStatus(resourceChan ResourceChan) {
glog.Infof("updateResourceStatus:%s", resourceChan.Type)
client := client.NewK8sClient()
switch resourceChan.Type {
case deployments:
deploy := deployment{k8sClient: client}
go updateStatus(&deploy, resourceChan)
case daemonsets:
ds := daemonset{k8sClient: client}
go updateStatus(&ds, resourceChan)
case statefulsets:
ss := statefulset{k8sClient: client}
go updateStatus(&ss, resourceChan)
case namespaces:
ns := namespace{k8sClient: client}
go updateStatus(&ns, resourceChan)
case ingresses:
ing := ingress{k8sClient: client}
go updateStatus(&ing, resourceChan)
case persistentVolumeClaim:
pvc := persistmentVolume{k8sClient: client}
go updateStatus(&pvc, resourceChan)
case roles:
r := role{k8sClient: client}
go updateStatus(&r, resourceChan)
case services:
svc := service{k8sClient: client}
go updateStatus(&svc, resourceChan)
case pods:
po := pod{k8sClient: client}
go updateStatus(&po, resourceChan)
}
}
func updateAllResourceStatus(resourceChans map[string]ResourceChan) {
for _, resourceChan := range resourceChans {
updateResourceStatus(resourceChan)
}
}
func receiveResourceStatus(resourceChans map[string]ResourceChan) {
defer func() {
close(stopChan)
}()
for {
for _, resourceChan := range resourceChans {
select {
case res, ok := <-resourceChan.StatusChan:
if !ok {
glog.Errorf("job:calculate %s' status have stopped", resourceChan.Type)
registerResource(resourceChans, resourceChan.Type)
updateResourceStatus(resourceChans[resourceChan.Type])
} else {
value, _ := json.Marshal(res)
key := constants.Root + "/" + res.ResourceType
etcdClient.Put(key, string(value))
}
default:
continue
}
}
}
}
func Run() {
glog.Info("Begin to submit resource status")
var err error
etcdClient, err = client.NewEtcdClient()
defer etcdClient.Close()
if err != nil {
glog.Error(err)
}
resourceChans := make(map[string]ResourceChan)
resourceList := []string{statefulsets, deployments, daemonsets, namespaces, ingresses, services, roles, persistentVolumeClaim, pods}
for _, resource := range resourceList {
registerResource(resourceChans, resource)
}
updateAllResourceStatus(resourceChans)
receiveResourceStatus(resourceChans)
}

View File

@@ -1,87 +0,0 @@
/*
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 resources
import (
"k8s.io/api/core/v1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type service struct {
k8sClient *kubernetes.Clientset
}
func (svc *service) list() (interface{}, error) {
list, err := svc.k8sClient.CoreV1().Services("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return list.Items, nil
}
func (svc *service) getWatcher() (watch.Interface, error) {
watcher, err := svc.k8sClient.CoreV1().Services("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (svc *service) generateObject(item v1.Service) OtherResourceObject {
name := item.Name
ns := item.Namespace
object := OtherResourceObject{Namespace: ns, Name: name}
return object
}
func (svc *service) updateWithObject(status *ResourceStatus, item v1.Service) {
namespace := item.Namespace
object := svc.generateObject(item)
status.ResourceList.update(namespace, object)
}
func (svc *service) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1.Service)
for _, item := range items {
svc.updateWithObject(status, item)
}
}
func (svc *service) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1.Service)
namespace := object.Namespace
tmpObject := svc.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, tmpObject)
return
}
svc.updateWithObject(status, *object)
}

View File

@@ -1,107 +0,0 @@
/*
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 resources
import (
"k8s.io/api/apps/v1beta2"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/kubernetes"
)
type statefulset struct {
k8sClient *kubernetes.Clientset
}
func (ss *statefulset) list() (interface{}, error) {
daemonsetList, err := ss.k8sClient.AppsV1beta2().StatefulSets("").List(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return daemonsetList.Items, nil
}
func (ss *statefulset) getWatcher() (watch.Interface, error) {
watcher, err := ss.k8sClient.AppsV1beta2().StatefulSets("").Watch(meta_v1.ListOptions{})
if err != nil {
return nil, err
}
return watcher, nil
}
func (ss *statefulset) generateObject(item v1beta2.StatefulSet) WorkLoadObject {
var app string
var ready bool
name := item.Name
namespace := item.Namespace
availablePodNum := item.Status.ReadyReplicas
desirePodNum := *item.Spec.Replicas
createTime := item.CreationTimestamp
release := item.ObjectMeta.Labels["release"]
chart := item.ObjectMeta.Labels["chart"]
if len(release) > 0 && len(chart) > 0 {
app = release + "/" + chart
} else {
app = "-"
}
if availablePodNum >= desirePodNum {
ready = true
} else {
ready = false
}
statefulSetObject := WorkLoadObject{Namespace: namespace, Name: name, Available: availablePodNum, Desire: desirePodNum,
App: app, CreateTime: createTime, Ready: ready}
return statefulSetObject
}
func (ss *statefulset) updateWithObject(status *ResourceStatus, item v1beta2.StatefulSet) {
namespace := item.Namespace
ssObject := ss.generateObject(item)
status.ResourceList.update(namespace, ssObject)
}
func (ss *statefulset) updateWithObjects(status *ResourceStatus, objects interface{}) {
if status.ResourceList == nil {
status.ResourceList = make(Resources)
}
items := objects.([]v1beta2.StatefulSet)
for _, item := range items {
ss.updateWithObject(status, item)
}
}
func (ss *statefulset) updateWithEvent(status *ResourceStatus, event watch.Event) {
object := event.Object.(*v1beta2.StatefulSet)
namespace := object.Namespace
ssObject := ss.generateObject(*object)
if event.Type == watch.Deleted {
status.ResourceList.del(namespace, ssObject)
return
}
ss.updateWithObject(status, *object)
}

View File

@@ -1,105 +0,0 @@
/*
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 resources
import (
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/watch"
)
type resource interface {
equal(object resource) bool
}
type resourcetList interface {
update(key string, value resource)
del(key string, value resource)
}
type ResourceStatus struct {
ResourceType string `json:"type"`
ResourceList resourcetList `json:"lists"`
UpdateTimeStamp int64 `json:"updateTimestamp"`
}
type ResourceChan struct {
Type string
StatusChan chan *ResourceStatus
StopChan chan struct{}
}
type Resource interface {
list() (interface{}, error)
getWatcher() (watch.Interface, error)
updateWithObjects(workload *ResourceStatus, objects interface{})
updateWithEvent(workload *ResourceStatus, event watch.Event)
}
type WorkLoadObject struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
App string `json:"app"`
Available int32 `json:"available"`
Desire int32 `json:"desire"`
Ready bool `json:"ready"`
NodeSelector map[string]string `json:"nodeSelector,omitempty"`
UpdateTime meta_v1.Time `json:"updateTime,omitempty"`
CreateTime meta_v1.Time `json:"createTime,omitempty"`
}
type OtherResourceObject struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
}
type Resources map[string][]resource
func (resources Resources) update(namespace string, object resource) {
for index, tmpObject := range resources[namespace] {
if tmpObject.equal(object) {
resources[namespace][index] = object
return
}
}
resources[namespace] = append(resources[namespace], object)
}
func (resources Resources) del(namespace string, object resource) {
for index, tmpObject := range resources[namespace] {
if tmpObject.equal(object) {
resources[namespace] = append(resources[namespace][:index], resources[namespace][index+1:]...)
return
}
}
}
func (workLoadObject WorkLoadObject) equal(object resource) bool {
tmp := object.(WorkLoadObject)
if workLoadObject.Name == tmp.Name && workLoadObject.Namespace == tmp.Namespace {
return true
}
return false
}
func (otherResourceObject OtherResourceObject) equal(object resource) bool {
tmp := object.(OtherResourceObject)
if otherResourceObject.Name == tmp.Name && otherResourceObject.Namespace == tmp.Namespace {
return true
}
return false
}

View File

@@ -17,50 +17,115 @@ limitations under the License.
package models
import (
"k8s.io/api/core/v1"
"encoding/json"
"errors"
"time"
"github.com/golang/glog"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/controllers"
)
const (
podsKey = "count/pods"
daemonsetsKey = "count/daemonsets.apps"
deploymentsKey = "count/deployments.apps"
ingressKey = "count/ingresses.extensions"
rolesKey = "count/roles.rbac.authorization.k8s.io"
clusterRolesKey = "count/cluster-role"
servicesKey = "count/services"
statefulsetsKey = "count/statefulsets.apps"
persistentvolumeclaimsKey = "persistentvolumeclaims"
storageClassesKey = "count/storageClass"
namespaceKey = "count/namespace"
)
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}
type resourceQuota struct {
NameSpace string `json:"namespace"`
Data v1.ResourceQuotaStatus `json:"data"`
UpdateTimeStamp int64 `json:"updateTimeStamp"`
NameSpace string `json:"namespace"`
Data v1.ResourceQuotaStatus `json:"data"`
}
func GetNamespaceQuota(namespace string) (*resourceQuota, error) {
cli, err := client.NewEtcdClient()
func getUsage(namespace, resource string) int {
ctl, err := getController(resource)
if err != nil {
glog.Error(err)
return 0
}
defer cli.Close()
key := constants.Root + "/" + constants.QuotaKey + "/" + namespace
value, err := cli.Get(key)
var data = v1.ResourceQuotaStatus{make(v1.ResourceList), make(v1.ResourceList)}
var res = resourceQuota{Data: data}
err = json.Unmarshal(value, &res)
if time.Now().Unix()-res.UpdateTimeStamp > 5*constants.UpdateCircle {
err = errors.New("internal server error")
return nil, err
}
if err != nil {
return nil, err
}
return &res, nil
return ctl.Count(namespace)
}
func GetClusterQuota() (*resourceQuota, error) {
return GetNamespaceQuota("\"\"")
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
for k, v := range resourceMap {
used := getUsage("", v)
var quantity resource.Quantity
quantity.Set(int64(used))
quota.Used[v1.ResourceName(k)] = quantity
}
return &resourceQuota{NameSpace: "\"\"", Data: quota}, nil
}
func GetNamespaceQuota(namespace string) (*resourceQuota, error) {
quota, err := getNamespaceResourceQuota(namespace)
if err != nil {
glog.Error(err)
return nil, err
}
if quota == nil {
quota = &v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
}
for k, v := range resourceMap {
if _, exist := quota.Used[v1.ResourceName(k)]; !exist {
if k == namespaceKey || k == storageClassesKey {
continue
}
used := getUsage(namespace, v)
var quantity resource.Quantity
quantity.Set(int64(used))
quota.Used[v1.ResourceName(k)] = quantity
}
}
return &resourceQuota{NameSpace: namespace, Data: *quota}, nil
}
func updateNamespaceQuota(tmpResourceList, resourceList v1.ResourceList) {
if tmpResourceList == nil {
tmpResourceList = resourceList
}
for resource, usage := range resourceList {
tmpUsage, exist := tmpResourceList[resource]
if !exist {
tmpResourceList[resource] = usage
}
if tmpUsage.Cmp(usage) == 1 {
tmpResourceList[resource] = usage
}
}
}
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
quotaList, err := client.NewK8sClient().CoreV1().ResourceQuotas(namespace).List(metaV1.ListOptions{})
if err != nil || len(quotaList.Items) == 0 {
return nil, err
}
quotaStatus := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
for _, quota := range quotaList.Items {
updateNamespaceQuota(quotaStatus.Hard, quota.Status.Hard)
updateNamespaceQuota(quotaStatus.Used, quota.Status.Used)
}
return &quotaStatus, nil
}

163
pkg/models/resources.go Normal file
View File

@@ -0,0 +1,163 @@
package models
import (
"errors"
"fmt"
"strconv"
"strings"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/models/controllers"
)
type ResourceList struct {
Total int `json:"total,omitempty"`
Page int `json:"page,omitempty"`
Limit int `json:"limit,omitempty"`
Items interface{} `json:"items,omitempty"`
}
func getController(resource string) (controllers.Controller, error) {
var ctl controllers.Controller
attr := controllers.CommonAttribute{DB: client.NewDBClient()}
switch resource {
case controllers.Deployments:
ctl = &controllers.DeploymentCtl{attr}
case controllers.Statefulsets:
ctl = &controllers.StatefulsetCtl{attr}
case controllers.Daemonsets:
ctl = &controllers.DaemonsetCtl{attr}
case controllers.Ingresses:
ctl = &controllers.IngressCtl{attr}
case controllers.PersistentVolumeClaim:
ctl = &controllers.PvcCtl{attr}
case controllers.Roles:
ctl = &controllers.RoleCtl{attr}
case controllers.ClusterRoles:
ctl = &controllers.ClusterRoleCtl{attr}
case controllers.Services:
ctl = &controllers.ServiceCtl{attr}
case controllers.Pods:
ctl = &controllers.PodCtl{attr}
case controllers.Namespaces:
ctl = &controllers.NamespaceCtl{attr}
case controllers.StorageClasses:
ctl = &controllers.StorageClassCtl{attr}
default:
return nil, errors.New("invalid resource type")
}
return ctl, nil
}
func getConditions(str string) (map[string]string, error) {
dict := make(map[string]string)
if len(str) == 0 {
return dict, nil
}
list := strings.Split(str, ",")
for _, item := range list {
kvs := strings.Split(item, "=")
if len(kvs) < 2 {
return nil, errors.New("invalid condition input")
}
dict[kvs[0]] = kvs[1]
}
return dict, nil
}
func getPaging(str string) (map[string]int, error) {
paging := make(map[string]int)
if len(str) == 0 {
return paging, nil
}
list := strings.Split(str, ",")
for _, item := range list {
kvs := strings.Split(item, "=")
if len(kvs) < 2 {
return nil, errors.New("invalid Paging input")
}
value, err := strconv.Atoi(kvs[1])
if err != nil {
return nil, err
}
paging[kvs[0]] = value
}
return paging, nil
}
func ListResource(resourceName, conditonSrt, pagingStr string) (*ResourceList, error) {
conditions, err := getConditions(conditonSrt)
if err != nil {
return nil, err
}
pagingMap, err := getPaging(pagingStr)
if err != nil {
return nil, err
}
conditionStr, paging := generateConditionAndPaging(conditions, pagingMap)
ctl, err := getController(resourceName)
if err != nil {
return nil, err
}
total, items, err := ctl.ListWithConditions(conditionStr, paging)
if err != nil {
return nil, err
}
return &ResourceList{Total: total, Items: items, Page: pagingMap["page"], Limit: pagingMap["limit"]}, nil
}
func generateConditionAndPaging(conditions map[string]string, paging map[string]int) (string, *controllers.Paging) {
conditionStr := ""
for k, v := range conditions {
if len(conditionStr) == 0 {
conditionStr = fmt.Sprintf("%s = \"%s\" ", k, v)
} else {
conditionStr = fmt.Sprintf("%s AND %s = \"%s\" ", conditionStr, k, v)
}
}
if paging["limit"] > 0 && paging["page"] >= 0 {
offset := (paging["page"] - 1) * paging["limit"]
return conditionStr, &controllers.Paging{Limit: paging["limit"], Offset: offset}
}
return conditionStr, nil
}
type workLoadStatus struct {
NameSpace string `json:"namespace"`
Count map[string]int `json:"data"`
Items map[string]interface{}
}
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
res := workLoadStatus{Count: make(map[string]int), NameSpace: namespace, Items: make(map[string]interface{})}
for _, resource := range []string{controllers.Deployments, controllers.Statefulsets, controllers.Daemonsets} {
status, err := ListResource(resource, "status=updating", "")
if err != nil {
return nil, err
}
count := status.Total
items := status.Items
res.Count[resource] = count
res.Items[resource] = items
}
return &res, nil
}
func GetClusterResourceStatus() (*workLoadStatus, error) {
return GetNamespacesResourceStatus("")
}

View File

@@ -1,70 +0,0 @@
/*
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 (
"encoding/json"
"errors"
"time"
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
)
type workLoadStatus struct {
NameSpace string `json:"namespace"`
Data map[string]int `json:"data"`
UpdateTimeStamp int64 `json:"updateTimeStamp"`
}
var resourceList = []string{"deployments", "daemonsets", "statefulsets"}
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
cli, err := client.NewEtcdClient()
if err != nil {
glog.Error(err)
return nil, err
}
defer cli.Close()
res := workLoadStatus{Data: make(map[string]int)}
key := constants.Root + "/" + constants.WorkloadStatusKey + "/" + namespace
value, err := cli.Get(key)
if err != nil {
return nil, err
}
err = json.Unmarshal(value, &res)
if err != nil {
return nil, err
}
if time.Now().Unix()-res.UpdateTimeStamp > 5*constants.UpdateCircle {
err = errors.New("data in etcd is too old")
return nil, err
}
return &res, nil
}
func GetClusterResourceStatus() (*workLoadStatus, error) {
return GetNamespacesResourceStatus("\"\"")
}