Initial commit
This commit is contained in:
204
pkg/models/components/components.go
Normal file
204
pkg/models/components/components.go
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 components
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
)
|
||||
|
||||
type Component struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
SelfLink string `json:"selfLink"`
|
||||
Label interface{} `json:"label"`
|
||||
StartedAt time.Time `json:"startedAt"`
|
||||
TotalBackends int `json:"totalBackends"`
|
||||
HealthyBackends int `json:"healthyBackends"`
|
||||
}
|
||||
|
||||
var (
|
||||
componentStatusLister lister.ComponentStatusLister
|
||||
serviceLister lister.ServiceLister
|
||||
podLister lister.PodLister
|
||||
nodeLister lister.NodeLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
componentStatusLister = informers.SharedInformerFactory().Core().V1().ComponentStatuses().Lister()
|
||||
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
nodeLister = informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
}
|
||||
|
||||
func GetComponentStatus(name string) (interface{}, error) {
|
||||
|
||||
var service *coreV1.Service
|
||||
var err error
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
service, err = serviceLister.Services(ns).Get(name)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pods, err := podLister.Pods(service.Namespace).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
component := Component{
|
||||
Name: service.Name,
|
||||
Namespace: service.Namespace,
|
||||
SelfLink: service.SelfLink,
|
||||
Label: service.Spec.Selector,
|
||||
StartedAt: service.CreationTimestamp.Time,
|
||||
HealthyBackends: 0,
|
||||
TotalBackends: 0,
|
||||
}
|
||||
for _, v := range pods {
|
||||
component.TotalBackends++
|
||||
component.HealthyBackends++
|
||||
for _, c := range v.Status.ContainerStatuses {
|
||||
if !c.Ready {
|
||||
component.HealthyBackends--
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return component, nil
|
||||
}
|
||||
|
||||
func GetSystemHealthStatus() (map[string]interface{}, error) {
|
||||
|
||||
status := make(map[string]interface{})
|
||||
|
||||
componentStatuses, err := componentStatusLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cs := range componentStatuses {
|
||||
status[cs.Name] = cs.Conditions[0]
|
||||
}
|
||||
|
||||
// get kubesphere-system components
|
||||
systemComponentStatus, err := GetAllComponentsStatus()
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
}
|
||||
|
||||
for k, v := range systemComponentStatus {
|
||||
status[k] = v
|
||||
}
|
||||
// get node status
|
||||
nodes, err := nodeLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return status, nil
|
||||
}
|
||||
|
||||
nodeStatus := make(map[string]int)
|
||||
totalNodes := 0
|
||||
healthyNodes := 0
|
||||
for _, nodes := range nodes {
|
||||
totalNodes++
|
||||
for _, condition := range nodes.Status.Conditions {
|
||||
if condition.Type == coreV1.NodeReady && condition.Status == coreV1.ConditionTrue {
|
||||
healthyNodes++
|
||||
}
|
||||
}
|
||||
}
|
||||
nodeStatus["totalNodes"] = totalNodes
|
||||
nodeStatus["healthyNodes"] = healthyNodes
|
||||
|
||||
status["nodes"] = nodeStatus
|
||||
|
||||
return status, nil
|
||||
|
||||
}
|
||||
|
||||
func GetAllComponentsStatus() (map[string]interface{}, error) {
|
||||
|
||||
status := make(map[string]interface{})
|
||||
|
||||
var err error
|
||||
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
|
||||
nsStatus := make(map[string]interface{})
|
||||
|
||||
services, err := serviceLister.Services(ns).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
component := Component{
|
||||
Name: service.Name,
|
||||
Namespace: service.Namespace,
|
||||
SelfLink: service.SelfLink,
|
||||
Label: service.Spec.Selector,
|
||||
StartedAt: service.CreationTimestamp.Time,
|
||||
HealthyBackends: 0,
|
||||
TotalBackends: 0,
|
||||
}
|
||||
|
||||
pods, err := podLister.Pods(ns).List(labels.SelectorFromValidatedSet(service.Spec.Selector))
|
||||
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, pod := range pods {
|
||||
component.TotalBackends++
|
||||
component.HealthyBackends++
|
||||
for _, c := range pod.Status.ContainerStatuses {
|
||||
if !c.Ready {
|
||||
component.HealthyBackends--
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsStatus[service.Name] = component
|
||||
}
|
||||
|
||||
if len(nsStatus) > 0 {
|
||||
status[ns] = nsStatus
|
||||
}
|
||||
}
|
||||
|
||||
return status, err
|
||||
}
|
||||
29
pkg/models/hpa/hpa.go
Normal file
29
pkg/models/hpa/hpa.go
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 hpa
|
||||
|
||||
import (
|
||||
"k8s.io/api/autoscaling/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
)
|
||||
|
||||
func GetHPA(namespace, hpa string) (*v1.HorizontalPodAutoscaler, error) {
|
||||
return client.K8sClient().AutoscalingV1().HorizontalPodAutoscalers(namespace).Get(hpa, metaV1.GetOptions{})
|
||||
}
|
||||
461
pkg/models/iam/iam.go
Normal file
461
pkg/models/iam/iam.go
Normal file
@@ -0,0 +1,461 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
v12 "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/rbac/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
ksErr "kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
const ClusterRoleKind = "ClusterRole"
|
||||
|
||||
var (
|
||||
clusterRoleBindingLister v12.ClusterRoleBindingLister
|
||||
clusterRoleLister v12.ClusterRoleLister
|
||||
roleBindingLister v12.RoleBindingLister
|
||||
roleLister v12.RoleLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
clusterRoleBindingLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
|
||||
clusterRoleLister = informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||
roleBindingLister = informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
|
||||
roleLister = informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
|
||||
}
|
||||
|
||||
// Get user list based on workspace role
|
||||
func WorkspaceRoleUsers(workspace string, roleName string) ([]User, error) {
|
||||
|
||||
workspaceRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
names := make([]string, 0)
|
||||
|
||||
for _, subject := range workspaceRoleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind {
|
||||
names = append(names, subject.Name)
|
||||
}
|
||||
}
|
||||
|
||||
users, err := GetUsers(names)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(users); i++ {
|
||||
users[i].WorkspaceRole = roleName
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUsers(names []string) ([]User, error) {
|
||||
var users []User
|
||||
|
||||
if names == nil || len(names) == 0 {
|
||||
return make([]User, 0), nil
|
||||
}
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &users)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetUser(name string) (*User, error) {
|
||||
|
||||
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
}
|
||||
|
||||
var user User
|
||||
|
||||
err = json.Unmarshal(data, &user)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) {
|
||||
|
||||
clusterRoles, err := GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
clusterRules := make([]v1.PolicyRule, 0)
|
||||
for _, role := range clusterRoles {
|
||||
clusterRules = append(clusterRules, role.Rules...)
|
||||
}
|
||||
|
||||
if requiredRule.Size() == 0 {
|
||||
if RulesMatchesRequired(clusterRules, v1.PolicyRule{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
}) {
|
||||
return true, nil, nil
|
||||
}
|
||||
} else {
|
||||
|
||||
if RulesMatchesRequired(clusterRules, requiredRule) {
|
||||
return true, nil, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
roles, err := GetRoles("", username)
|
||||
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
rulesMapping := make(map[string][]v1.PolicyRule, 0)
|
||||
|
||||
for _, role := range roles {
|
||||
rules := rulesMapping[role.Namespace]
|
||||
if rules == nil {
|
||||
rules = make([]v1.PolicyRule, 0)
|
||||
}
|
||||
rules = append(rules, role.Rules...)
|
||||
rulesMapping[role.Namespace] = rules
|
||||
}
|
||||
|
||||
namespaces = make([]string, 0)
|
||||
|
||||
for namespace, rules := range rulesMapping {
|
||||
if requiredRule.Size() == 0 || RulesMatchesRequired(rules, requiredRule) {
|
||||
namespaces = append(namespaces, namespace)
|
||||
}
|
||||
}
|
||||
|
||||
return false, namespaces, nil
|
||||
}
|
||||
|
||||
func GetRole(namespace string, name string) (*v1.Role, error) {
|
||||
role, err := roleLister.Roles(namespace).Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return role.DeepCopy(), nil
|
||||
}
|
||||
|
||||
func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) {
|
||||
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, workspaceRole))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
users := make([]string, 0)
|
||||
|
||||
for _, s := range clusterRoleBinding.Subjects {
|
||||
if s.Kind == v1.UserKind && !slice.ContainsString(users, s.Name, nil) {
|
||||
users = append(users, s.Name)
|
||||
}
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func GetClusterRole(name string) (*v1.ClusterRole, error) {
|
||||
|
||||
role, err := clusterRoleLister.Get(name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role.DeepCopy(), nil
|
||||
}
|
||||
|
||||
func GetRoles(namespace string, username string) ([]v1.Role, error) {
|
||||
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := make([]v1.Role, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
|
||||
role.Namespace = roleBinding.Namespace
|
||||
roles = append(roles, role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
glog.Infoln(err.Error())
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
} else {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
role, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
roles = append(roles, *role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
glog.Infoln(err.Error())
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
// Get cluster roles by username
|
||||
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := make([]v1.ClusterRole, 0)
|
||||
|
||||
for _, roleBinding := range clusterRoleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
||||
if err == nil {
|
||||
role = role.DeepCopy()
|
||||
if role.Annotations == nil {
|
||||
role.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name
|
||||
if roleBinding.Annotations != nil &&
|
||||
roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == roleBinding.RoleRef.Name {
|
||||
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
|
||||
}
|
||||
roles = append(roles, *role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
glog.Warning(err)
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
|
||||
for _, rule := range rules {
|
||||
if ruleMatchesRequired(rule, required) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool {
|
||||
|
||||
if len(required.NonResourceURLs) == 0 {
|
||||
for _, apiGroup := range required.APIGroups {
|
||||
for _, resource := range required.Resources {
|
||||
resources := strings.Split(resource, "/")
|
||||
resource = resources[0]
|
||||
var subsource string
|
||||
if len(resources) > 1 {
|
||||
subsource = resources[1]
|
||||
}
|
||||
|
||||
if len(required.ResourceNames) == 0 {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, resourceName := range required.ResourceNames {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, apiGroup := range required.APIGroups {
|
||||
for _, nonResourceURL := range required.NonResourceURLs {
|
||||
for _, verb := range required.Verbs {
|
||||
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
|
||||
|
||||
if resource == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.ResourceAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) {
|
||||
return false
|
||||
}
|
||||
|
||||
combinedResource := resource
|
||||
|
||||
if subresource != "" {
|
||||
combinedResource = combinedResource + "/" + subresource
|
||||
}
|
||||
|
||||
for _, res := range rule.Resources {
|
||||
|
||||
// match "*"
|
||||
if res == v1.ResourceAll || res == combinedResource {
|
||||
return true
|
||||
}
|
||||
|
||||
// match "*/subresource"
|
||||
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
|
||||
return true
|
||||
}
|
||||
// match "resource/*"
|
||||
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func ruleMatchesRequest(rule v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
|
||||
|
||||
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, v1.VerbAll) {
|
||||
return false
|
||||
}
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
|
||||
} else {
|
||||
return ruleMatchesNonResource(rule, nonResourceURL)
|
||||
}
|
||||
}
|
||||
|
||||
func ruleMatchesNonResource(rule v1.PolicyRule, nonResourceURL string) bool {
|
||||
|
||||
if nonResourceURL == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, spec := range rule.NonResourceURLs {
|
||||
if pathMatches(nonResourceURL, spec) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func pathMatches(path, spec string) bool {
|
||||
// Allow wildcard match
|
||||
if spec == "*" {
|
||||
return true
|
||||
}
|
||||
// Allow exact match
|
||||
if spec == path {
|
||||
return true
|
||||
}
|
||||
// Allow a trailing * subpath match
|
||||
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasString(slice []string, value string) bool {
|
||||
for _, s := range slice {
|
||||
if s == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
39
pkg/models/iam/types.go
Normal file
39
pkg/models/iam/types.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package iam
|
||||
|
||||
import (
|
||||
"k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
type Action struct {
|
||||
Name string `json:"name"`
|
||||
Rules []v1.PolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
type Rule struct {
|
||||
Name string `json:"name"`
|
||||
Actions []Action `json:"actions"`
|
||||
}
|
||||
|
||||
type SimpleRule struct {
|
||||
Name string `json:"name"`
|
||||
Actions []string `json:"actions"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
Groups []string `json:"groups"`
|
||||
Password string `json:"password,omitempty"`
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
Description string `json:"description"`
|
||||
Email string `json:"email"`
|
||||
LastLoginTime string `json:"last_login_time"`
|
||||
Status int `json:"status"`
|
||||
ClusterRole string `json:"cluster_role"`
|
||||
ClusterRules []SimpleRule `json:"cluster_rules,omitempty"`
|
||||
Roles map[string]string `json:"roles,omitempty"`
|
||||
Rules map[string][]SimpleRule `json:"rules,omitempty"`
|
||||
Role string `json:"role,omitempty"`
|
||||
WorkspaceRoles map[string]string `json:"workspace_roles,omitempty"`
|
||||
WorkspaceRole string `json:"workspace_role,omitempty"`
|
||||
WorkspaceRules map[string][]SimpleRule `json:"workspace_rules,omitempty"`
|
||||
}
|
||||
294
pkg/models/kubeconfig/kubeconfig.go
Normal file
294
pkg/models/kubeconfig/kubeconfig.go
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 kubeconfig
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
rd "math/rand"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"gopkg.in/yaml.v2"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
caPath = "/etc/kubernetes/pki/ca.crt"
|
||||
keyPath = "/etc/kubernetes/pki/ca.key"
|
||||
clusterName = "kubernetes"
|
||||
kubectlConfigKey = "config"
|
||||
defaultNamespace = "default"
|
||||
)
|
||||
|
||||
type clusterInfo struct {
|
||||
CertificateAuthorityData string `yaml:"certificate-authority-data"`
|
||||
Server string `yaml:"server"`
|
||||
}
|
||||
|
||||
type cluster struct {
|
||||
Cluster clusterInfo `yaml:"cluster"`
|
||||
Name string `yaml:"name"`
|
||||
}
|
||||
|
||||
type contextInfo struct {
|
||||
Cluster string `yaml:"cluster"`
|
||||
User string `yaml:"user"`
|
||||
NameSpace string `yaml:"namespace"`
|
||||
}
|
||||
|
||||
type contextObject struct {
|
||||
Context contextInfo `yaml:"context"`
|
||||
Name string `yaml:"name"`
|
||||
}
|
||||
|
||||
type userInfo struct {
|
||||
CaData string `yaml:"client-certificate-data"`
|
||||
KeyData string `yaml:"client-key-data"`
|
||||
}
|
||||
|
||||
type user struct {
|
||||
Name string `yaml:"name"`
|
||||
User userInfo `yaml:"user"`
|
||||
}
|
||||
|
||||
type kubeConfig struct {
|
||||
ApiVersion string `yaml:"apiVersion"`
|
||||
Clusters []cluster `yaml:"clusters"`
|
||||
Contexts []contextObject `yaml:"contexts"`
|
||||
CurrentContext string `yaml:"current-context"`
|
||||
Kind string `yaml:"kind"`
|
||||
Preferences map[string]string `yaml:"preferences"`
|
||||
Users []user `yaml:"users"`
|
||||
}
|
||||
|
||||
type CertInformation struct {
|
||||
Country []string
|
||||
Organization []string
|
||||
OrganizationalUnit []string
|
||||
EmailAddress []string
|
||||
Province []string
|
||||
Locality []string
|
||||
CommonName string
|
||||
CrtName, KeyName string
|
||||
IsCA bool
|
||||
Names []pkix.AttributeTypeAndValue
|
||||
}
|
||||
|
||||
func createCRT(RootCa *x509.Certificate, RootKey *rsa.PrivateKey, info CertInformation) ([]byte, []byte, error) {
|
||||
var cert, key bytes.Buffer
|
||||
Crt := newCertificate(info)
|
||||
Key, err := rsa.GenerateKey(rand.Reader, 2048)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
|
||||
buf, err = x509.CreateCertificate(rand.Reader, Crt, RootCa, &Key.PublicKey, RootKey)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
pem.Encode(&cert, &pem.Block{Type: "CERTIFICATE", Bytes: buf})
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
buf = x509.MarshalPKCS1PrivateKey(Key)
|
||||
pem.Encode(&key, &pem.Block{Type: "PRIVATE KEY", Bytes: buf})
|
||||
|
||||
return cert.Bytes(), key.Bytes(), nil
|
||||
}
|
||||
|
||||
func Parse(crtPath, keyPath string) (rootcertificate *x509.Certificate, rootPrivateKey *rsa.PrivateKey, err error) {
|
||||
rootcertificate, err = parseCrt(crtPath)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, nil, err
|
||||
}
|
||||
rootPrivateKey, err = parseKey(keyPath)
|
||||
return rootcertificate, rootPrivateKey, nil
|
||||
}
|
||||
|
||||
func parseCrt(path string) (*x509.Certificate, error) {
|
||||
buf, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
p := &pem.Block{}
|
||||
p, buf = pem.Decode(buf)
|
||||
return x509.ParseCertificate(p.Bytes)
|
||||
}
|
||||
|
||||
func parseKey(path string) (*rsa.PrivateKey, error) {
|
||||
buf, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
p, buf := pem.Decode(buf)
|
||||
return x509.ParsePKCS1PrivateKey(p.Bytes)
|
||||
}
|
||||
|
||||
func newCertificate(info CertInformation) *x509.Certificate {
|
||||
rd.Seed(time.Now().UnixNano())
|
||||
return &x509.Certificate{
|
||||
SerialNumber: big.NewInt(rd.Int63()),
|
||||
Subject: pkix.Name{
|
||||
Country: info.Country,
|
||||
Organization: info.Organization,
|
||||
OrganizationalUnit: info.OrganizationalUnit,
|
||||
Province: info.Province,
|
||||
CommonName: info.CommonName,
|
||||
Locality: info.Locality,
|
||||
ExtraNames: info.Names,
|
||||
},
|
||||
NotBefore: time.Now(),
|
||||
NotAfter: time.Now().AddDate(20, 0, 0),
|
||||
BasicConstraintsValid: true,
|
||||
IsCA: info.IsCA,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
|
||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
|
||||
EmailAddresses: info.EmailAddress,
|
||||
}
|
||||
}
|
||||
|
||||
func generateCaAndKey(user, caPath, keyPath string) (string, string, error) {
|
||||
crtInfo := CertInformation{CommonName: user, IsCA: false}
|
||||
|
||||
crt, pri, err := Parse(caPath, keyPath)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return "", "", err
|
||||
}
|
||||
cert, key, err := createCRT(crt, pri, crtInfo)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return "", "", err
|
||||
}
|
||||
|
||||
base64Cert := base64.StdEncoding.EncodeToString(cert)
|
||||
base64Key := base64.StdEncoding.EncodeToString(key)
|
||||
return base64Cert, base64Key, nil
|
||||
}
|
||||
|
||||
func createKubeConfig(userName string) (string, error) {
|
||||
tmpKubeConfig := kubeConfig{ApiVersion: "v1", Kind: "Config"}
|
||||
serverCa, err := ioutil.ReadFile(caPath)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return "", err
|
||||
}
|
||||
base64ServerCa := base64.StdEncoding.EncodeToString(serverCa)
|
||||
tmpClusterInfo := clusterInfo{CertificateAuthorityData: base64ServerCa, Server: client.KubeConfig.Host}
|
||||
tmpCluster := cluster{Cluster: tmpClusterInfo, Name: clusterName}
|
||||
tmpKubeConfig.Clusters = append(tmpKubeConfig.Clusters, tmpCluster)
|
||||
|
||||
contextName := userName + "@" + clusterName
|
||||
tmpContext := contextObject{Context: contextInfo{User: userName, Cluster: clusterName, NameSpace: defaultNamespace}, Name: contextName}
|
||||
tmpKubeConfig.Contexts = append(tmpKubeConfig.Contexts, tmpContext)
|
||||
|
||||
cert, key, err := generateCaAndKey(userName, caPath, keyPath)
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tmpUser := user{User: userInfo{CaData: cert, KeyData: key}, Name: userName}
|
||||
tmpKubeConfig.Users = append(tmpKubeConfig.Users, tmpUser)
|
||||
tmpKubeConfig.CurrentContext = contextName
|
||||
|
||||
config, err := yaml.Marshal(tmpKubeConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(config), nil
|
||||
}
|
||||
|
||||
func CreateKubeConfig(user string) error {
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
|
||||
|
||||
if errors.IsNotFound(err) {
|
||||
config, err := createKubeConfig(user)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
data := map[string]string{"config": string(config)}
|
||||
configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: user}, Data: data}
|
||||
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
|
||||
if err != nil && !errors.IsAlreadyExists(err) {
|
||||
glog.Errorf("create user %s's kubeConfig failed, reason: %s", user, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func GetKubeConfig(user string) (string, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
glog.Errorf("cannot get user %s's kubeConfig, reason: %s", user, err)
|
||||
return "", err
|
||||
}
|
||||
return configMap.Data[kubectlConfigKey], nil
|
||||
}
|
||||
|
||||
func DelKubeConfig(user string) error {
|
||||
k8sClient := client.K8sClient()
|
||||
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
deletePolicy := metaV1.DeletePropagationBackground
|
||||
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
if err != nil {
|
||||
glog.Errorf("delete user %s's kubeConfig failed, reason: %s", user, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
156
pkg/models/kubectl/kubectl.go
Normal file
156
pkg/models/kubectl/kubectl.go
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 kubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/apps/v1beta2"
|
||||
"k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
namespace = constants.KubeSphereControlNamespace
|
||||
)
|
||||
|
||||
type PodInfo struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Pod string `json:"pod"`
|
||||
Container string `json:"container"`
|
||||
}
|
||||
|
||||
func GetKubectlPod(username string) (PodInfo, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
}
|
||||
|
||||
selectors := deploy.Spec.Selector.MatchLabels
|
||||
labelSelector := labels.Set(selectors).AsSelector().String()
|
||||
podList, err := k8sClient.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
}
|
||||
|
||||
pod, err := selectCorrectPod(namespace, podList.Items)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return PodInfo{}, err
|
||||
}
|
||||
|
||||
info := PodInfo{Namespace: pod.Namespace, Pod: pod.Name, Container: pod.Status.ContainerStatuses[0].Name}
|
||||
|
||||
return info, nil
|
||||
|
||||
}
|
||||
|
||||
func selectCorrectPod(namespace string, pods []v1.Pod) (kubectlPod v1.Pod, err error) {
|
||||
|
||||
var kubectlPodList []v1.Pod
|
||||
for _, pod := range pods {
|
||||
for _, condition := range pod.Status.Conditions {
|
||||
if condition.Type == "Ready" && condition.Status == "True" {
|
||||
kubectlPodList = append(kubectlPodList, pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(kubectlPodList) < 1 {
|
||||
err = fmt.Errorf("cannot find valid kubectl pod in namespace:%s", namespace)
|
||||
return v1.Pod{}, err
|
||||
}
|
||||
|
||||
random := rand.Intn(len(kubectlPodList))
|
||||
return kubectlPodList[random], nil
|
||||
}
|
||||
|
||||
func CreateKubectlDeploy(user string) error {
|
||||
k8sClient := client.K8sClient()
|
||||
_, err := k8sClient.AppsV1().Deployments(namespace).Get(user, metav1.GetOptions{})
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
replica := int32(1)
|
||||
selector := metav1.LabelSelector{MatchLabels: map[string]string{"user": user}}
|
||||
config := v1.ConfigMapVolumeSource{Items: []v1.KeyToPath{{Key: "config", Path: "config"}}, LocalObjectReference: v1.LocalObjectReference{Name: user}}
|
||||
deployment := v1beta2.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: user,
|
||||
},
|
||||
Spec: v1beta2.DeploymentSpec{
|
||||
Replicas: &replica,
|
||||
Selector: &selector,
|
||||
Template: v1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{
|
||||
"user": user,
|
||||
},
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{Name: "kubectl",
|
||||
Image: "",
|
||||
VolumeMounts: []v1.VolumeMount{{Name: "kubeconfig", MountPath: "/root/.kube"}},
|
||||
},
|
||||
},
|
||||
Volumes: []v1.Volume{{Name: "kubeconfig", VolumeSource: v1.VolumeSource{ConfigMap: &config}}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
_, err = k8sClient.AppsV1beta2().Deployments(namespace).Create(&deployment)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func DelKubectlDeploy(user string) error {
|
||||
k8sClient := client.K8sClient()
|
||||
_, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(user, metav1.GetOptions{})
|
||||
if errors.IsNotFound(err) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
err := fmt.Errorf("delete user %s failed, reason:%v", user, err)
|
||||
return err
|
||||
}
|
||||
|
||||
deletePolicy := metav1.DeletePropagationBackground
|
||||
|
||||
err = k8sClient.AppsV1beta2().Deployments(namespace).Delete(user, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
if err != nil {
|
||||
err := fmt.Errorf("delete user %s failed, reason:%v", user, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
1011
pkg/models/metrics/metrics.go
Normal file
1011
pkg/models/metrics/metrics.go
Normal file
File diff suppressed because it is too large
Load Diff
200
pkg/models/metrics/metricsrule.go
Normal file
200
pkg/models/metrics/metricsrule.go
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
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 metrics
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func MakeWorkloadPromQL(metricName, nsName, wlFilter string) string {
|
||||
if wlFilter == "" {
|
||||
wlFilter = ".*"
|
||||
}
|
||||
|
||||
var promql = RulePromQLTmplMap[metricName]
|
||||
promql = strings.Replace(promql, "$2", nsName, -1)
|
||||
promql = strings.Replace(promql, "$3", wlFilter, -1)
|
||||
return promql
|
||||
}
|
||||
|
||||
func MakeSpecificWorkloadRule(wkKind, wkName, namespace string) string {
|
||||
var rule = PodInfoRule
|
||||
if namespace == "" {
|
||||
namespace = ".*"
|
||||
}
|
||||
// alertnatives values: Deployment StatefulSet ReplicaSet DaemonSet
|
||||
wkKind = strings.ToLower(wkKind)
|
||||
|
||||
switch wkKind {
|
||||
case "deployment":
|
||||
wkKind = ReplicaSet
|
||||
if wkName != "" {
|
||||
wkName = "~\"^" + wkName + `-(\\w)+$"`
|
||||
} else {
|
||||
wkName = "~\".*\""
|
||||
}
|
||||
rule = strings.Replace(rule, "$1", wkKind, -1)
|
||||
rule = strings.Replace(rule, "$2", wkName, -1)
|
||||
rule = strings.Replace(rule, "$3", namespace, -1)
|
||||
return rule
|
||||
case "replicaset":
|
||||
wkKind = ReplicaSet
|
||||
case "statefulset":
|
||||
wkKind = StatefulSet
|
||||
case "daemonset":
|
||||
wkKind = DaemonSet
|
||||
}
|
||||
|
||||
if wkName == "" {
|
||||
wkName = "~\".*\""
|
||||
} else {
|
||||
wkName = "\"" + wkName + "\""
|
||||
}
|
||||
|
||||
rule = strings.Replace(rule, "$1", wkKind, -1)
|
||||
rule = strings.Replace(rule, "$2", wkName, -1)
|
||||
rule = strings.Replace(rule, "$3", namespace, -1)
|
||||
return rule
|
||||
}
|
||||
|
||||
func MakeAllWorkspacesPromQL(metricsName, nsFilter string) string {
|
||||
|
||||
var promql = RulePromQLTmplMap[metricsName]
|
||||
nsFilter = "!~\"" + nsFilter + "\""
|
||||
promql = strings.Replace(promql, "$1", nsFilter, -1)
|
||||
return promql
|
||||
}
|
||||
|
||||
func MakeSpecificWorkspacePromQL(metricsName, nsFilter string) string {
|
||||
|
||||
var promql = RulePromQLTmplMap[metricsName]
|
||||
nsFilter = "=~\"" + nsFilter + "\""
|
||||
promql = strings.Replace(promql, "$1", nsFilter, -1)
|
||||
return promql
|
||||
}
|
||||
|
||||
func MakeContainerPromQL(nsName, nodeId, podName, containerName, metricName, containerFilter string) string {
|
||||
var promql string
|
||||
|
||||
if nsName != "" {
|
||||
// get container metrics from namespace-pod
|
||||
promql = RulePromQLTmplMap[metricName]
|
||||
promql = strings.Replace(promql, "$1", nsName, -1)
|
||||
} else {
|
||||
// get container metrics from node-pod
|
||||
promql = RulePromQLTmplMap[metricName+"_node"]
|
||||
promql = strings.Replace(promql, "$1", nodeId, -1)
|
||||
}
|
||||
|
||||
promql = strings.Replace(promql, "$2", podName, -1)
|
||||
|
||||
if containerName == "" {
|
||||
|
||||
if containerFilter == "" {
|
||||
containerFilter = ".*"
|
||||
}
|
||||
promql = strings.Replace(promql, "$3", containerFilter, -1)
|
||||
} else {
|
||||
promql = strings.Replace(promql, "$3", containerName, -1)
|
||||
}
|
||||
|
||||
return promql
|
||||
}
|
||||
|
||||
func MakePodPromQL(metricName, nsName, nodeID, podName, podFilter string) string {
|
||||
|
||||
if podFilter == "" {
|
||||
podFilter = ".*"
|
||||
}
|
||||
|
||||
var promql = ""
|
||||
if nsName != "" {
|
||||
// get pod metrics by namespace
|
||||
if podName != "" {
|
||||
// specific pod
|
||||
promql = RulePromQLTmplMap[metricName]
|
||||
promql = strings.Replace(promql, "$1", nsName, -1)
|
||||
promql = strings.Replace(promql, "$2", podName, -1)
|
||||
|
||||
} else {
|
||||
// all pods
|
||||
metricName += "_all"
|
||||
promql = RulePromQLTmplMap[metricName]
|
||||
|
||||
promql = strings.Replace(promql, "$1", nsName, -1)
|
||||
promql = strings.Replace(promql, "$2", podFilter, -1)
|
||||
}
|
||||
} else if nodeID != "" {
|
||||
// get pod metrics by nodeid
|
||||
metricName += "_node"
|
||||
promql = RulePromQLTmplMap[metricName]
|
||||
promql = strings.Replace(promql, "$3", nodeID, -1)
|
||||
if podName != "" {
|
||||
// specific pod
|
||||
promql = strings.Replace(promql, "$2", podName, -1)
|
||||
} else {
|
||||
promql = strings.Replace(promql, "$2", podFilter, -1)
|
||||
}
|
||||
}
|
||||
return promql
|
||||
}
|
||||
|
||||
func MakeNamespacePromQL(nsName string, nsFilter string, metricsName string) string {
|
||||
var recordingRule = RulePromQLTmplMap[metricsName]
|
||||
|
||||
if nsName != "" {
|
||||
nsFilter = nsName
|
||||
} else {
|
||||
if nsFilter == "" {
|
||||
nsFilter = ".*"
|
||||
}
|
||||
}
|
||||
recordingRule = strings.Replace(recordingRule, "$1", nsFilter, -1)
|
||||
return recordingRule
|
||||
}
|
||||
|
||||
// cluster rule
|
||||
func MakeClusterRule(metricsName string) string {
|
||||
var rule = RulePromQLTmplMap[metricsName]
|
||||
return rule
|
||||
}
|
||||
|
||||
// node rule
|
||||
func MakeNodeRule(nodeID string, nodesFilter string, metricsName string) string {
|
||||
var rule = RulePromQLTmplMap[metricsName]
|
||||
|
||||
if nodesFilter == "" {
|
||||
nodesFilter = ".*"
|
||||
}
|
||||
if strings.Contains(metricsName, "disk_size") || strings.Contains(metricsName, "pod") || strings.Contains(metricsName, "usage") || strings.Contains(metricsName, "inode") || strings.Contains(metricsName, "load") {
|
||||
// disk size promql
|
||||
if nodeID != "" {
|
||||
nodesFilter = "{" + "node" + "=" + "\"" + nodeID + "\"" + "}"
|
||||
} else {
|
||||
nodesFilter = "{" + "node" + "=~" + "\"" + nodesFilter + "\"" + "}"
|
||||
}
|
||||
rule = strings.Replace(rule, "$1", nodesFilter, -1)
|
||||
} else {
|
||||
// cpu, memory, network, disk_iops rules
|
||||
if nodeID != "" {
|
||||
// specific node
|
||||
rule = rule + "{" + "node" + "=" + "\"" + nodeID + "\"" + "}"
|
||||
} else {
|
||||
// all nodes or specific nodes filted with re2 syntax
|
||||
rule = rule + "{" + "node" + "=~" + "\"" + nodesFilter + "\"" + "}"
|
||||
}
|
||||
}
|
||||
|
||||
return rule
|
||||
}
|
||||
579
pkg/models/metrics/metricsruleconst.go
Normal file
579
pkg/models/metrics/metricsruleconst.go
Normal file
@@ -0,0 +1,579 @@
|
||||
/*
|
||||
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 metrics
|
||||
|
||||
const (
|
||||
ResultTypeVector = "vector"
|
||||
ResultTypeMatrix = "matrix"
|
||||
MetricStatus = "status"
|
||||
MetricStatusError = "error"
|
||||
MetricStatusSuccess = "success"
|
||||
ResultItemMetric = "metric"
|
||||
ResultItemMetricResource = "resource"
|
||||
ResultItemValue = "value"
|
||||
ResultItemValues = "values"
|
||||
ResultSortTypeDesc = "desc"
|
||||
ResultSortTypeAsc = "asc"
|
||||
)
|
||||
|
||||
const (
|
||||
MetricNameWorkloadCount = "workload_count"
|
||||
MetricNameNamespacePodCount = "namespace_pod_count"
|
||||
|
||||
MetricNameWorkspaceAllOrganizationCount = "workspace_all_organization_count"
|
||||
MetricNameWorkspaceAllAccountCount = "workspace_all_account_count"
|
||||
MetricNameWorkspaceAllProjectCount = "workspace_all_project_count"
|
||||
MetricNameWorkspaceAllDevopsCount = "workspace_all_devops_project_count"
|
||||
MetricNameClusterAllProjectCount = "cluster_namespace_count"
|
||||
|
||||
MetricNameWorkspaceNamespaceCount = "workspace_namespace_count"
|
||||
MetricNameWorkspaceDevopsCount = "workspace_devops_project_count"
|
||||
MetricNameWorkspaceMemberCount = "workspace_member_count"
|
||||
MetricNameWorkspaceRoleCount = "workspace_role_count"
|
||||
MetricNameComponentOnLine = "component_online_count"
|
||||
MetricNameComponentLine = "component_count"
|
||||
)
|
||||
|
||||
const (
|
||||
WorkspaceResourceKindOrganization = "organization"
|
||||
WorkspaceResourceKindAccount = "account"
|
||||
WorkspaceResourceKindNamespace = "namespace"
|
||||
WorkspaceResourceKindDevops = "devops"
|
||||
WorkspaceResourceKindMember = "member"
|
||||
WorkspaceResourceKindRole = "role"
|
||||
)
|
||||
|
||||
const (
|
||||
MetricLevelCluster = "cluster"
|
||||
MetricLevelClusterWorkspace = "cluster_workspace"
|
||||
MetricLevelNode = "node"
|
||||
MetricLevelWorkspace = "workspace"
|
||||
MetricLevelNamespace = "namespace"
|
||||
MetricLevelPod = "pod"
|
||||
MetricLevelPodName = "pod_name"
|
||||
MetricLevelContainer = "container"
|
||||
MetricLevelContainerName = "container_name"
|
||||
MetricLevelWorkload = "workload"
|
||||
)
|
||||
|
||||
const (
|
||||
ReplicaSet = "ReplicaSet"
|
||||
StatefulSet = "StatefulSet"
|
||||
DaemonSet = "DaemonSet"
|
||||
Deployment = "Deployment"
|
||||
)
|
||||
|
||||
const (
|
||||
NodeStatusRule = `kube_node_status_condition{condition="Ready"} > 0`
|
||||
PodInfoRule = `kube_pod_info{created_by_kind="$1",created_by_name=$2,namespace="$3"}`
|
||||
NamespaceLabelRule = `kube_namespace_labels`
|
||||
WorkloadReplicaSetOwnerRule = `kube_pod_owner{namespace="$1", owner_name!="<none>", owner_kind="ReplicaSet"}`
|
||||
WorkspaceNamespaceLabelRule = `sum(kube_namespace_labels{label_kubesphere_io_workspace != ""}) by (label_kubesphere_io_workspace)`
|
||||
ExcludedVirtualNetworkInterfaces = `interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)"`
|
||||
)
|
||||
|
||||
const (
|
||||
WorkspaceJoinedKey = "label_kubesphere_io_workspace"
|
||||
)
|
||||
|
||||
type MetricMap map[string]string
|
||||
|
||||
var ClusterMetricsNames = []string{
|
||||
"cluster_cpu_utilisation",
|
||||
"cluster_cpu_usage",
|
||||
"cluster_cpu_total",
|
||||
"cluster_memory_utilisation",
|
||||
"cluster_memory_available",
|
||||
"cluster_memory_total",
|
||||
"cluster_memory_usage_wo_cache",
|
||||
"cluster_net_utilisation",
|
||||
"cluster_net_bytes_transmitted",
|
||||
"cluster_net_bytes_received",
|
||||
"cluster_disk_read_iops",
|
||||
"cluster_disk_write_iops",
|
||||
"cluster_disk_read_throughput",
|
||||
"cluster_disk_write_throughput",
|
||||
"cluster_disk_size_usage",
|
||||
"cluster_disk_size_utilisation",
|
||||
"cluster_disk_size_capacity",
|
||||
"cluster_disk_size_available",
|
||||
"cluster_disk_inode_total",
|
||||
"cluster_disk_inode_usage",
|
||||
"cluster_disk_inode_utilisation",
|
||||
|
||||
"cluster_node_online",
|
||||
"cluster_node_offline",
|
||||
"cluster_node_total",
|
||||
|
||||
"cluster_pod_count",
|
||||
"cluster_pod_quota",
|
||||
"cluster_pod_utilisation",
|
||||
"cluster_pod_running_count",
|
||||
"cluster_pod_succeeded_count",
|
||||
"cluster_pod_abnormal_count",
|
||||
"cluster_ingresses_extensions_count",
|
||||
"cluster_cronjob_count",
|
||||
"cluster_pvc_count",
|
||||
"cluster_daemonset_count",
|
||||
"cluster_deployment_count",
|
||||
"cluster_endpoint_count",
|
||||
"cluster_hpa_count",
|
||||
"cluster_job_count",
|
||||
"cluster_statefulset_count",
|
||||
"cluster_replicaset_count",
|
||||
"cluster_service_count",
|
||||
"cluster_secret_count",
|
||||
|
||||
"cluster_namespace_count",
|
||||
|
||||
"cluster_load1",
|
||||
"cluster_load5",
|
||||
"cluster_load15",
|
||||
}
|
||||
var NodeMetricsNames = []string{
|
||||
"node_cpu_utilisation",
|
||||
"node_cpu_total",
|
||||
"node_cpu_usage",
|
||||
"node_memory_utilisation",
|
||||
"node_memory_usage_wo_cache",
|
||||
"node_memory_available",
|
||||
"node_memory_total",
|
||||
|
||||
"node_net_utilisation",
|
||||
"node_net_bytes_transmitted",
|
||||
"node_net_bytes_received",
|
||||
"node_disk_read_iops",
|
||||
"node_disk_write_iops",
|
||||
"node_disk_read_throughput",
|
||||
"node_disk_write_throughput",
|
||||
"node_disk_size_capacity",
|
||||
"node_disk_size_available",
|
||||
"node_disk_size_usage",
|
||||
"node_disk_size_utilisation",
|
||||
|
||||
"node_disk_inode_total",
|
||||
"node_disk_inode_usage",
|
||||
"node_disk_inode_utilisation",
|
||||
|
||||
"node_pod_count",
|
||||
"node_pod_quota",
|
||||
"node_pod_utilisation",
|
||||
"node_pod_running_count",
|
||||
"node_pod_succeeded_count",
|
||||
"node_pod_abnormal_count",
|
||||
|
||||
"node_load1",
|
||||
"node_load5",
|
||||
"node_load15",
|
||||
}
|
||||
var WorkspaceMetricsNames = []string{
|
||||
"workspace_cpu_usage",
|
||||
"workspace_memory_usage",
|
||||
"workspace_memory_usage_wo_cache",
|
||||
"workspace_net_bytes_transmitted",
|
||||
"workspace_net_bytes_received",
|
||||
"workspace_pod_count",
|
||||
"workspace_pod_running_count",
|
||||
"workspace_pod_succeeded_count",
|
||||
"workspace_pod_abnormal_count",
|
||||
"workspace_ingresses_extensions_count",
|
||||
|
||||
"workspace_cronjob_count",
|
||||
"workspace_pvc_count",
|
||||
"workspace_daemonset_count",
|
||||
"workspace_deployment_count",
|
||||
"workspace_endpoint_count",
|
||||
"workspace_hpa_count",
|
||||
"workspace_job_count",
|
||||
"workspace_statefulset_count",
|
||||
"workspace_replicaset_count",
|
||||
"workspace_service_count",
|
||||
"workspace_secret_count",
|
||||
|
||||
"workspace_all_project_count",
|
||||
}
|
||||
var NamespaceMetricsNames = []string{
|
||||
"namespace_cpu_usage",
|
||||
"namespace_memory_usage",
|
||||
"namespace_memory_usage_wo_cache",
|
||||
"namespace_net_bytes_transmitted",
|
||||
"namespace_net_bytes_received",
|
||||
"namespace_pod_count",
|
||||
"namespace_pod_running_count",
|
||||
"namespace_pod_succeeded_count",
|
||||
"namespace_pod_abnormal_count",
|
||||
|
||||
"namespace_configmap_count_used",
|
||||
"namespace_jobs_batch_count_used",
|
||||
"namespace_roles_count_used",
|
||||
"namespace_memory_limit_used",
|
||||
"namespace_pvc_used",
|
||||
"namespace_memory_request_used",
|
||||
"namespace_pvc_count_used",
|
||||
"namespace_cronjobs_batch_count_used",
|
||||
"namespace_ingresses_extensions_count_used",
|
||||
"namespace_cpu_limit_used",
|
||||
"namespace_storage_request_used",
|
||||
"namespace_deployment_count_used",
|
||||
"namespace_pod_count_used",
|
||||
"namespace_statefulset_count_used",
|
||||
"namespace_daemonset_count_used",
|
||||
"namespace_secret_count_used",
|
||||
"namespace_service_count_used",
|
||||
"namespace_cpu_request_used",
|
||||
"namespace_service_loadbalancer_used",
|
||||
|
||||
"namespace_configmap_count_hard",
|
||||
"namespace_jobs_batch_count_hard",
|
||||
"namespace_roles_count_hard",
|
||||
"namespace_memory_limit_hard",
|
||||
"namespace_pvc_hard",
|
||||
"namespace_memory_request_hard",
|
||||
"namespace_pvc_count_hard",
|
||||
"namespace_cronjobs_batch_count_hard",
|
||||
"namespace_ingresses_extensions_count_hard",
|
||||
"namespace_cpu_limit_hard",
|
||||
"namespace_storage_request_hard",
|
||||
"namespace_deployment_count_hard",
|
||||
"namespace_pod_count_hard",
|
||||
"namespace_statefulset_count_hard",
|
||||
"namespace_daemonset_count_hard",
|
||||
"namespace_secret_count_hard",
|
||||
"namespace_service_count_hard",
|
||||
"namespace_cpu_request_hard",
|
||||
"namespace_service_loadbalancer_hard",
|
||||
|
||||
"namespace_cronjob_count",
|
||||
"namespace_pvc_count",
|
||||
"namespace_daemonset_count",
|
||||
"namespace_deployment_count",
|
||||
"namespace_endpoint_count",
|
||||
"namespace_hpa_count",
|
||||
"namespace_job_count",
|
||||
"namespace_statefulset_count",
|
||||
"namespace_replicaset_count",
|
||||
"namespace_service_count",
|
||||
"namespace_secret_count",
|
||||
|
||||
"namespace_ingresses_extensions_count",
|
||||
}
|
||||
|
||||
var PodMetricsNames = []string{
|
||||
"pod_cpu_usage",
|
||||
"pod_memory_usage",
|
||||
"pod_memory_usage_wo_cache",
|
||||
"pod_net_bytes_transmitted",
|
||||
"pod_net_bytes_received",
|
||||
}
|
||||
|
||||
var WorkloadMetricsNames = []string{
|
||||
"workload_pod_cpu_usage",
|
||||
"workload_pod_memory_usage",
|
||||
"workload_pod_memory_usage_wo_cache",
|
||||
"workload_pod_net_bytes_transmitted",
|
||||
"workload_pod_net_bytes_received",
|
||||
|
||||
"workload_deployment_replica",
|
||||
"workload_deployment_replica_available",
|
||||
"workload_statefulset_replica",
|
||||
"workload_statefulset_replica_available",
|
||||
"workload_daemonset_replica",
|
||||
"workload_daemonset_replica_available",
|
||||
}
|
||||
|
||||
var ContainerMetricsNames = []string{
|
||||
"container_cpu_usage",
|
||||
"container_memory_usage",
|
||||
"container_memory_usage_wo_cache",
|
||||
//"container_net_bytes_transmitted",
|
||||
//"container_net_bytes_received",
|
||||
}
|
||||
|
||||
var RulePromQLTmplMap = MetricMap{
|
||||
//cluster
|
||||
"cluster_cpu_utilisation": ":node_cpu_utilisation:avg1m",
|
||||
"cluster_cpu_usage": `:node_cpu_utilisation:avg1m * sum(node:node_num_cpu:sum)`,
|
||||
"cluster_cpu_total": "sum(node:node_num_cpu:sum)",
|
||||
"cluster_memory_utilisation": ":node_memory_utilisation:",
|
||||
"cluster_memory_available": "sum(node:node_memory_bytes_available:sum)",
|
||||
"cluster_memory_total": "sum(node:node_memory_bytes_total:sum)",
|
||||
"cluster_memory_usage_wo_cache": "sum(node:node_memory_bytes_total:sum) - sum(node:node_memory_bytes_available:sum)",
|
||||
|
||||
"cluster_net_utilisation": ":node_net_utilisation:sum_irate",
|
||||
"cluster_net_bytes_transmitted": "sum(node:node_net_bytes_transmitted:sum_irate)",
|
||||
"cluster_net_bytes_received": "sum(node:node_net_bytes_received:sum_irate)",
|
||||
"cluster_disk_read_iops": "sum(node:data_volume_iops_reads:sum)",
|
||||
"cluster_disk_write_iops": "sum(node:data_volume_iops_writes:sum)",
|
||||
"cluster_disk_read_throughput": "sum(node:data_volume_throughput_bytes_read:sum)",
|
||||
"cluster_disk_write_throughput": "sum(node:data_volume_throughput_bytes_written:sum)",
|
||||
|
||||
"cluster_disk_size_usage": `sum(max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_utilisation": `1 - sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node)) / sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_capacity": `sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_available": `sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
|
||||
"cluster_disk_inode_total": `sum(node:disk_inodes_total:)`,
|
||||
"cluster_disk_inode_usage": `sum(node:disk_inodes_total:) - sum(node:disk_inodes_free:)`,
|
||||
"cluster_disk_inode_utilisation": `1 - sum(node:disk_inodes_free:) / sum(node:disk_inodes_total:)`,
|
||||
|
||||
"cluster_namespace_count": `count(kube_namespace_annotations)`,
|
||||
|
||||
// cluster_pod_count = cluster_pod_running_count + cluster_pod_succeeded_count + cluster_pod_abnormal_count
|
||||
"cluster_pod_count": `sum((kube_pod_status_scheduled{condition="true"} > 0) * on (namespace, pod) group_left(node) (sum by (node, namespace, pod) (kube_pod_info)) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"cluster_pod_quota": `sum(kube_node_status_capacity_pods unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"cluster_pod_utilisation": `sum(kube_pod_info unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)) / sum(kube_node_status_capacity_pods unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"cluster_pod_running_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Succeeded"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"cluster_pod_succeeded_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Running"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"cluster_pod_abnormal_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Succeeded|Running"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
|
||||
"cluster_node_online": `sum(kube_node_status_condition{condition="Ready",status="true"})`,
|
||||
"cluster_node_offline": `sum(kube_node_status_condition{condition="Ready",status=~"unknown|false"})`,
|
||||
"cluster_node_total": `sum(kube_node_status_condition{condition="Ready"})`,
|
||||
|
||||
"cluster_ingresses_extensions_count": `sum(kube_ingress_labels)`,
|
||||
|
||||
"cluster_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/configmaps"}) by (resource, type)`,
|
||||
"cluster_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/jobs.batch"}) by (resource, type)`,
|
||||
"cluster_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/roles.rbac.authorization.k8s.io"}) by (resource, type)`,
|
||||
"cluster_memory_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="limits.memory"}) by (resource, type)`,
|
||||
"cluster_pvc_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="persistentvolumeclaims"}) by (resource, type)`,
|
||||
"cluster_memory_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="requests.memory"}) by (resource, type)`,
|
||||
"cluster_pvc_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/persistentvolumeclaims"}) by (resource, type)`,
|
||||
"cluster_cronjobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/cronjobs.batch"}) by (resource, type)`,
|
||||
"cluster_ingresses_extensions_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/ingresses.extensions"}) by (resource, type)`,
|
||||
"cluster_cpu_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="limits.cpu"}) by (resource, type)`,
|
||||
"cluster_storage_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="requests.storage"}) by (resource, type)`,
|
||||
"cluster_deployment_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/deployments.apps"}) by (resource, type)`,
|
||||
"cluster_pod_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/pods"}) by (resource, type)`,
|
||||
"cluster_statefulset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/statefulsets.apps"}) by (resource, type)`,
|
||||
"cluster_daemonset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/daemonsets.apps"}) by (resource, type)`,
|
||||
"cluster_secret_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/secrets"}) by (resource, type)`,
|
||||
"cluster_service_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/services"}) by (resource, type)`,
|
||||
"cluster_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="requests.cpu"}) by (resource, type)`,
|
||||
"cluster_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="services.loadbalancers"}) by (resource, type)`,
|
||||
|
||||
"cluster_cronjob_count": `sum(kube_cronjob_labels)`,
|
||||
"cluster_pvc_count": `sum(kube_persistentvolumeclaim_info)`,
|
||||
"cluster_daemonset_count": `sum(kube_daemonset_labels)`,
|
||||
"cluster_deployment_count": `sum(kube_deployment_labels)`,
|
||||
"cluster_endpoint_count": `sum(kube_endpoint_labels)`,
|
||||
"cluster_hpa_count": `sum(kube_hpa_labels)`,
|
||||
"cluster_job_count": `sum(kube_job_labels)`,
|
||||
"cluster_statefulset_count": `sum(kube_statefulset_labels)`,
|
||||
"cluster_replicaset_count": `count(kube_replicaset_created)`,
|
||||
"cluster_service_count": `sum(kube_service_info)`,
|
||||
"cluster_secret_count": `sum(kube_secret_info)`,
|
||||
"cluster_pv_count": `sum(kube_persistentvolume_labels)`,
|
||||
|
||||
"cluster_load1": `sum(node_load1{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
|
||||
"cluster_load5": `sum(node_load5{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
|
||||
"cluster_load15": `sum(node_load15{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
|
||||
|
||||
//node
|
||||
"node_cpu_utilisation": "node:node_cpu_utilisation:avg1m",
|
||||
"node_cpu_total": "node:node_num_cpu:sum",
|
||||
"node_memory_utilisation": "node:node_memory_utilisation:",
|
||||
"node_memory_available": "node:node_memory_bytes_available:sum",
|
||||
"node_memory_total": "node:node_memory_bytes_total:sum",
|
||||
"node_memory_usage_wo_cache": "node:node_memory_bytes_total:sum$1 - node:node_memory_bytes_available:sum$1",
|
||||
|
||||
"node_net_utilisation": "node:node_net_utilisation:sum_irate",
|
||||
"node_net_bytes_transmitted": "node:node_net_bytes_transmitted:sum_irate",
|
||||
"node_net_bytes_received": "node:node_net_bytes_received:sum_irate",
|
||||
"node_disk_read_iops": "node:data_volume_iops_reads:sum",
|
||||
"node_disk_write_iops": "node:data_volume_iops_writes:sum",
|
||||
"node_disk_read_throughput": "node:data_volume_throughput_bytes_read:sum",
|
||||
"node_disk_write_throughput": "node:data_volume_throughput_bytes_written:sum",
|
||||
|
||||
"node_disk_size_capacity": `max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_available": `max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_usage": `max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_utilisation": `max(((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) / node_filesystem_size{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
|
||||
"node_disk_inode_total": `node:disk_inodes_total:$1`,
|
||||
"node_disk_inode_usage": `node:disk_inodes_total:$1 - node:disk_inodes_free:$1`,
|
||||
"node_disk_inode_utilisation": `(1 - (node:disk_inodes_free:$1 / node:disk_inodes_total:$1))`,
|
||||
|
||||
"node_pod_count": `sum by (node) ((kube_pod_status_scheduled{condition="true"} > 0) * on (namespace, pod) group_left(node) kube_pod_info$1 unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"node_pod_quota": `sum(kube_node_status_capacity_pods$1) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
|
||||
"node_pod_utilisation": `(sum(kube_pod_info$1) by (node) / sum(kube_node_status_capacity_pods$1) by (node)) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
|
||||
"node_pod_running_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Succeeded"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
|
||||
"node_pod_succeeded_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Running"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
|
||||
"node_pod_abnormal_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Succeeded|Running"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
|
||||
|
||||
// without log node: unless on(node) kube_node_labels{label_role="log"}
|
||||
"node_cpu_usage": `node:node_cpu_utilisation:avg1m$1 * node:node_num_cpu:sum$1`,
|
||||
|
||||
"node_load1": `sum by (node) (node_load1{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
|
||||
"node_load5": `sum by (node) (node_load5{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
|
||||
"node_load15": `sum by (node) (node_load15{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
|
||||
|
||||
//namespace
|
||||
"namespace_cpu_usage": `namespace:container_cpu_usage_seconds_total:sum_rate{namespace!="", namespace=~"$1"} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_memory_usage": `namespace:container_memory_usage_bytes:sum{namespace!="", namespace=~"$1"} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_memory_usage_wo_cache": `namespace:container_memory_usage_bytes_wo_cache:sum{namespace!="", namespace=~"$1"}* on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_net_bytes_transmitted": `sum by (namespace) (irate(container_network_transmit_bytes_total{namespace!="", namespace=~"$1", pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))* on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_net_bytes_received": `sum by (namespace) (irate(container_network_receive_bytes_total{namespace!="", namespace=~"$1", pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pod_count": `sum(kube_pod_status_phase{phase!~"Failed|Succeeded", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pod_running_count": `sum(kube_pod_status_phase{phase="Running", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pod_succeeded_count": `sum(kube_pod_status_phase{phase="Succeeded", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pod_abnormal_count": `sum(kube_pod_status_phase{phase=~"Failed|Pending|Unknown", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
|
||||
"namespace_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_memory_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pvc_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_memory_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pvc_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_cronjobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_ingresses_extensions_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_cpu_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_storage_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_deployment_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pod_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_statefulset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_daemonset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_secret_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_service_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
|
||||
"namespace_configmap_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_jobs_batch_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_roles_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_memory_limit_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pvc_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_memory_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pvc_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_cronjobs_batch_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_ingresses_extensions_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_cpu_limit_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_storage_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_deployment_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pod_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_statefulset_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_daemonset_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_secret_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_service_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_cpu_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_service_loadbalancer_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
|
||||
"namespace_cronjob_count": `sum(kube_cronjob_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_pvc_count": `sum(kube_persistentvolumeclaim_info{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_daemonset_count": `sum(kube_daemonset_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_deployment_count": `sum(kube_deployment_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_endpoint_count": `sum(kube_endpoint_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_hpa_count": `sum(kube_hpa_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_job_count": `sum(kube_job_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_statefulset_count": `sum(kube_statefulset_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_replicaset_count": `count(kube_replicaset_created{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_service_count": `sum(kube_service_info{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
"namespace_secret_count": `sum(kube_secret_info{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
|
||||
"namespace_ingresses_extensions_count": `sum(kube_ingress_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
|
||||
|
||||
// pod
|
||||
"pod_cpu_usage": `sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""}[5m])) by (namespace, pod_name)`,
|
||||
"pod_memory_usage": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""}) by (namespace, pod_name)`,
|
||||
"pod_memory_usage_wo_cache": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""} - container_memory_cache{job="kubelet", namespace="$1", pod_name!="", pod_name="$2",image!=""}) by (namespace, pod_name)`,
|
||||
"pod_net_bytes_transmitted": `sum by (namespace, pod_name) (irate(container_network_transmit_bytes_total{namespace="$1", pod_name!="", pod_name="$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
|
||||
"pod_net_bytes_received": `sum by (namespace, pod_name) (irate(container_network_receive_bytes_total{namespace="$1", pod_name!="", pod_name="$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
|
||||
|
||||
"pod_cpu_usage_all": `sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""}[5m])) by (namespace, pod_name)`,
|
||||
"pod_memory_usage_all": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""}) by (namespace, pod_name)`,
|
||||
"pod_memory_usage_wo_cache_all": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""} - container_memory_cache{job="kubelet", namespace="$1", pod_name!="", pod_name=~"$2", image!=""}) by (namespace, pod_name)`,
|
||||
"pod_net_bytes_transmitted_all": `sum by (namespace, pod_name) (irate(container_network_transmit_bytes_total{namespace="$1", pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
|
||||
"pod_net_bytes_received_all": `sum by (namespace, pod_name) (irate(container_network_receive_bytes_total{namespace="$1", pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]))`,
|
||||
|
||||
"pod_cpu_usage_node": `sum by (node, pod_name) (irate(container_cpu_usage_seconds_total{job="kubelet",pod_name!="", pod_name=~"$2", image!=""}[5m]) * on (namespace, pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
|
||||
"pod_memory_usage_node": `sum by (node, pod_name) (container_memory_usage_bytes{job="kubelet",pod_name!="", pod_name=~"$2", image!=""} * on (namespace, pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
|
||||
"pod_memory_usage_wo_cache_node": `sum by (node, pod_name) ((container_memory_usage_bytes{job="kubelet",pod_name!="", pod_name=~"$2", image!=""} - container_memory_cache{job="kubelet",pod_name!="", pod_name=~"$2", image!=""}) * on (namespace, pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
|
||||
"pod_net_bytes_transmitted_node": `sum by (node, pod_name) (irate(container_network_transmit_bytes_total{pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
|
||||
"pod_net_bytes_received_node": `sum by (node, pod_name) (irate(container_network_receive_bytes_total{pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
|
||||
|
||||
// workload
|
||||
"workload_pod_cpu_usage": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_pod_memory_usage": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(container_memory_usage_bytes{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_pod_memory_usage_wo_cache": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(container_memory_usage_bytes{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""} - container_memory_cache{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_pod_net_bytes_transmitted": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_network_transmit_bytes_total{namespace="$2", pod_name!="", pod_name=~"$3", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_pod_net_bytes_received": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_network_receive_bytes_total{namespace="$2", pod_name!="", pod_name=~"$3", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
|
||||
|
||||
"workload_deployment_replica": `label_join(sum (label_join(label_replace(kube_deployment_spec_replicas{namespace="$2", deployment=~"$3"}, "owner_kind", "Deployment", "", ""), "workload", "", "deployment")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_deployment_replica_available": `label_join(sum (label_join(label_replace(kube_deployment_status_replicas_available{namespace="$2", deployment=~"$3"}, "owner_kind", "Deployment", "", ""), "workload", "", "deployment")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_statefulset_replica": `label_join(sum (label_join(label_replace(kube_statefulset_replicas{namespace="$2", statefulset=~"$3"}, "owner_kind", "StatefulSet", "", ""), "workload", "", "statefulset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_statefulset_replica_available": `label_join(sum (label_join(label_replace(kube_statefulset_status_replicas_current{namespace="$2", statefulset=~"$3"}, "owner_kind", "StatefulSet", "", ""), "workload", "", "statefulset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_daemonset_replica": `label_join(sum (label_join(label_replace(kube_daemonset_status_desired_number_scheduled{namespace="$2", daemonset=~"$3"}, "owner_kind", "DaemonSet", "", ""), "workload", "", "daemonset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
|
||||
"workload_daemonset_replica_available": `label_join(sum (label_join(label_replace(kube_daemonset_status_number_available{namespace="$2", daemonset=~"$3"}, "owner_kind", "DaemonSet", "", ""), "workload", "", "daemonset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
|
||||
|
||||
// container
|
||||
"container_cpu_usage": `sum(irate(container_cpu_usage_seconds_total{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}[5m])) by (namespace, pod_name, container_name)`,
|
||||
"container_memory_usage": `sum(container_memory_usage_bytes{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}) by (namespace, pod_name, container_name)`,
|
||||
"container_memory_usage_wo_cache": `container_memory_usage_bytes{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"} - ignoring(id, image, endpoint, instance, job, name, service) container_memory_cache{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}`,
|
||||
"container_net_bytes_transmitted": `sum(irate(container_network_transmit_bytes_total{job="kubelet", namespace="$1", pod_name="$2", container_name="POD", ` + ExcludedVirtualNetworkInterfaces + `}[5m])) by (namespace, pod_name, container_name)`,
|
||||
"container_net_bytes_received": `sum(irate(container_network_receive_bytes_total{job="kubelet", namespace="$1", pod_name="$2", container_name="POD", ` + ExcludedVirtualNetworkInterfaces + `}[5m])) by (namespace, pod_name, container_name)`,
|
||||
|
||||
"container_cpu_usage_node": `sum by (node, pod_name, container_name) (irate(container_cpu_usage_seconds_total{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
|
||||
"container_memory_usage_node": `sum by (node, pod_name, container_name) (container_memory_usage_bytes{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""} * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
|
||||
"container_memory_usage_wo_cache_node": `sum by (node, pod_name, container_name) ((container_memory_usage_bytes{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""} - container_memory_cache{job="kubelet", pod_name="$2", container_name!="POD", container_name!="", container_name=~"$3", image!=""}) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
|
||||
"container_net_bytes_transmitted_node": `sum by (node, pod_name, container_name) (irate(container_network_transmit_bytes_total{job="kubelet", ` + ExcludedVirtualNetworkInterfaces + `, pod_name="$2", container_name="POD", container_name!="", image!=""}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
|
||||
"container_net_bytes_received_node": `sum by (node, pod_name, container_name) (irate(container_network_receive_bytes_total{job="kubelet", ` + ExcludedVirtualNetworkInterfaces + `, pod_name="$2", container_name="POD", container_name!="", image!=""}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$1"}, "pod_name", "", "pod", "_name"))`,
|
||||
|
||||
// workspace
|
||||
"workspace_cpu_usage": `sum(namespace:container_cpu_usage_seconds_total:sum_rate{namespace!="", namespace$1})`,
|
||||
"workspace_memory_usage": `sum(namespace:container_memory_usage_bytes:sum{namespace!="", namespace$1})`,
|
||||
"workspace_memory_usage_wo_cache": `sum(namespace:container_memory_usage_bytes_wo_cache:sum{namespace!="", namespace$1})`,
|
||||
"workspace_net_bytes_transmitted": `sum(sum by (namespace) (irate(container_network_transmit_bytes_total{namespace!="", namespace$1, pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])))`,
|
||||
"workspace_net_bytes_received": `sum(sum by (namespace) (irate(container_network_receive_bytes_total{namespace!="", namespace$1, pod_name!="", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])))`,
|
||||
"workspace_pod_count": `sum(kube_pod_status_phase{phase!~"Failed|Succeeded", namespace!="", namespace$1})`,
|
||||
"workspace_pod_running_count": `sum(kube_pod_status_phase{phase="Running", namespace!="", namespace$1})`,
|
||||
"workspace_pod_succeeded_count": `sum(kube_pod_status_phase{phase="Succeeded", namespace!="", namespace$1})`,
|
||||
"workspace_pod_abnormal_count": `sum(kube_pod_status_phase{phase=~"Failed|Pending|Unknown", namespace!="", namespace$1})`,
|
||||
|
||||
"workspace_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/configmaps"}) by (resource, type)`,
|
||||
"workspace_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/jobs.batch"}) by (resource, type)`,
|
||||
"workspace_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/roles.rbac.authorization.k8s.io"}) by (resource, type)`,
|
||||
"workspace_memory_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="limits.memory"}) by (resource, type)`,
|
||||
"workspace_pvc_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="persistentvolumeclaims"}) by (resource, type)`,
|
||||
"workspace_memory_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="requests.memory"}) by (resource, type)`,
|
||||
"workspace_pvc_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/persistentvolumeclaims"}) by (resource, type)`,
|
||||
"workspace_cronjobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/cronjobs.batch"}) by (resource, type)`,
|
||||
"workspace_ingresses_extensions_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/ingresses.extensions"}) by (resource, type)`,
|
||||
"workspace_cpu_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="limits.cpu"}) by (resource, type)`,
|
||||
"workspace_storage_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="requests.storage"}) by (resource, type)`,
|
||||
"workspace_deployment_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/deployments.apps"}) by (resource, type)`,
|
||||
"workspace_pod_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/pods"}) by (resource, type)`,
|
||||
"workspace_statefulset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/statefulsets.apps"}) by (resource, type)`,
|
||||
"workspace_daemonset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/daemonsets.apps"}) by (resource, type)`,
|
||||
"workspace_secret_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/secrets"}) by (resource, type)`,
|
||||
"workspace_service_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="count/services"}) by (resource, type)`,
|
||||
"workspace_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="requests.cpu"}) by (resource, type)`,
|
||||
"workspace_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace$1, resource="services.loadbalancers"}) by (resource, type)`,
|
||||
|
||||
"workspace_ingresses_extensions_count": `sum(kube_ingress_labels{namespace!="", namespace$1})`,
|
||||
|
||||
"workspace_cronjob_count": `sum(kube_cronjob_labels{namespace!="", namespace$1})`,
|
||||
"workspace_pvc_count": `sum(kube_persistentvolumeclaim_info{namespace!="", namespace$1})`,
|
||||
"workspace_daemonset_count": `sum(kube_daemonset_labels{namespace!="", namespace$1})`,
|
||||
"workspace_deployment_count": `sum(kube_deployment_labels{namespace!="", namespace$1})`,
|
||||
"workspace_endpoint_count": `sum(kube_endpoint_labels{namespace!="", namespace$1})`,
|
||||
"workspace_hpa_count": `sum(kube_hpa_labels{namespace!="", namespace$1})`,
|
||||
"workspace_job_count": `sum(kube_job_labels{namespace!="", namespace$1})`,
|
||||
"workspace_statefulset_count": `sum(kube_statefulset_labels{namespace!="", namespace$1})`,
|
||||
"workspace_replicaset_count": `count(kube_replicaset_created{namespace!="", namespace$1})`,
|
||||
"workspace_service_count": `sum(kube_service_info{namespace!="", namespace$1})`,
|
||||
"workspace_secret_count": `sum(kube_secret_info{namespace!="", namespace$1})`,
|
||||
|
||||
"workspace_all_project_count": `count(kube_namespace_annotations)`,
|
||||
}
|
||||
51
pkg/models/metrics/namespaces.go
Normal file
51
pkg/models/metrics/namespaces.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
)
|
||||
|
||||
func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
|
||||
var nsNameList []string
|
||||
for i := range namespaces {
|
||||
nsNameList = append(nsNameList, namespaces[i].Name)
|
||||
}
|
||||
nsFilter := "^(" + strings.Join(nsNameList, "|") + ")$"
|
||||
var timeRelateParams = make(url.Values)
|
||||
|
||||
params := client.MonitoringRequestParams{
|
||||
NsFilter: nsFilter,
|
||||
Params: timeRelateParams,
|
||||
QueryType: client.DefaultQueryType,
|
||||
MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
|
||||
}
|
||||
|
||||
rawMetrics := MonitorAllMetrics(¶ms, MetricLevelNamespace)
|
||||
|
||||
for _, result := range rawMetrics.Results {
|
||||
for _, data := range result.Data.Result {
|
||||
metricDescMap, ok := data["metric"].(map[string]interface{})
|
||||
if ok {
|
||||
if ns, exist := metricDescMap["namespace"]; exist {
|
||||
timeAndValue, ok := data["value"].([]interface{})
|
||||
if ok && len(timeAndValue) == 2 {
|
||||
for i := 0; i < len(namespaces); i++ {
|
||||
if namespaces[i].Name == ns {
|
||||
if namespaces[i].Annotations == nil {
|
||||
namespaces[i].Annotations = make(map[string]string, 0)
|
||||
}
|
||||
namespaces[i].Annotations[result.MetricName] = timeAndValue[1].(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return namespaces
|
||||
}
|
||||
306
pkg/models/metrics/util.go
Normal file
306
pkg/models/metrics/util.go
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
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 metrics
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sort"
|
||||
"strconv"
|
||||
"unicode"
|
||||
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultPageLimit = 5
|
||||
DefaultPage = 1
|
||||
)
|
||||
|
||||
type FormatedMetricDataWrapper struct {
|
||||
fmtMetricData FormatedMetricData
|
||||
by func(p, q *map[string]interface{}) bool
|
||||
}
|
||||
|
||||
func (wrapper FormatedMetricDataWrapper) Len() int {
|
||||
return len(wrapper.fmtMetricData.Result)
|
||||
}
|
||||
|
||||
func (wrapper FormatedMetricDataWrapper) Less(i, j int) bool {
|
||||
return wrapper.by(&wrapper.fmtMetricData.Result[i], &wrapper.fmtMetricData.Result[j])
|
||||
}
|
||||
|
||||
func (wrapper FormatedMetricDataWrapper) Swap(i, j int) {
|
||||
wrapper.fmtMetricData.Result[i], wrapper.fmtMetricData.Result[j] = wrapper.fmtMetricData.Result[j], wrapper.fmtMetricData.Result[i]
|
||||
}
|
||||
|
||||
// sorted metric by ascending or descending order
|
||||
func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelMetric, resourceType string) (*FormatedLevelMetric, int) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
glog.Errorln(err)
|
||||
debug.PrintStack()
|
||||
}
|
||||
}()
|
||||
|
||||
if sortMetricName == "" {
|
||||
return fmtLevelMetric, -1
|
||||
}
|
||||
|
||||
// default sort type is descending order
|
||||
if sortType == "" {
|
||||
sortType = ResultSortTypeDesc
|
||||
}
|
||||
|
||||
var currentResourceMap = make(map[string]int)
|
||||
|
||||
// indexMap store sorted index for each node/namespace/pod
|
||||
var indexMap = make(map[string]int)
|
||||
i := 0
|
||||
for _, metricItem := range fmtLevelMetric.Results {
|
||||
if metricItem.Data.ResultType == ResultTypeVector && metricItem.Status == MetricStatusSuccess {
|
||||
if metricItem.MetricName == sortMetricName {
|
||||
if sortType == ResultSortTypeAsc {
|
||||
// desc
|
||||
sort.Sort(FormatedMetricDataWrapper{metricItem.Data, func(p, q *map[string]interface{}) bool {
|
||||
value1 := (*p)[ResultItemValue].([]interface{})
|
||||
value2 := (*q)[ResultItemValue].([]interface{})
|
||||
v1, _ := strconv.ParseFloat(value1[len(value1)-1].(string), 64)
|
||||
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
|
||||
if v1 == v2 {
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
return resourceName1.(string) < resourceName2.(string)
|
||||
}
|
||||
|
||||
return v1 < v2
|
||||
}})
|
||||
} else {
|
||||
// desc
|
||||
sort.Sort(FormatedMetricDataWrapper{metricItem.Data, func(p, q *map[string]interface{}) bool {
|
||||
value1 := (*p)[ResultItemValue].([]interface{})
|
||||
value2 := (*q)[ResultItemValue].([]interface{})
|
||||
v1, _ := strconv.ParseFloat(value1[len(value1)-1].(string), 64)
|
||||
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
|
||||
|
||||
if v1 == v2 {
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
return resourceName1.(string) > resourceName2.(string)
|
||||
}
|
||||
|
||||
return v1 > v2
|
||||
}})
|
||||
}
|
||||
|
||||
for _, r := range metricItem.Data.Result {
|
||||
// for some reasons, 'metric' may not contain `resourceType` field
|
||||
// example: {"metric":{},"value":[1541142931.731,"3"]}
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
key := k.(string)
|
||||
if exist {
|
||||
if _, exist := indexMap[key]; !exist {
|
||||
indexMap[key] = i
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// iterator all metric to find max metricItems length
|
||||
for _, r := range metricItem.Data.Result {
|
||||
k, ok := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
if ok {
|
||||
currentResourceMap[k.(string)] = 1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for k := range currentResourceMap {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, resource := range keys {
|
||||
if _, exist := indexMap[resource]; !exist {
|
||||
indexMap[resource] = i
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
// sort other metric
|
||||
for i := 0; i < len(fmtLevelMetric.Results); i++ {
|
||||
re := fmtLevelMetric.Results[i]
|
||||
if re.Data.ResultType == ResultTypeVector && re.Status == MetricStatusSuccess {
|
||||
sortedMetric := make([]map[string]interface{}, len(indexMap))
|
||||
for j := 0; j < len(re.Data.Result); j++ {
|
||||
r := re.Data.Result[j]
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
if exist {
|
||||
index, exist := indexMap[k.(string)]
|
||||
if exist {
|
||||
sortedMetric[index] = r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmtLevelMetric.Results[i].Data.Result = sortedMetric
|
||||
}
|
||||
}
|
||||
|
||||
return fmtLevelMetric, len(indexMap)
|
||||
}
|
||||
|
||||
func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric, maxLength int) interface{} {
|
||||
if maxLength <= 0 {
|
||||
return fmtLevelMetric
|
||||
}
|
||||
// matrix type can not be sorted
|
||||
for _, metricItem := range fmtLevelMetric.Results {
|
||||
// if metric reterieved field, resultType is ""
|
||||
if metricItem.Data.ResultType == ResultTypeMatrix {
|
||||
return fmtLevelMetric
|
||||
}
|
||||
}
|
||||
|
||||
var page = DefaultPage
|
||||
|
||||
if pageNum != "" {
|
||||
p, err := strconv.Atoi(pageNum)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
} else {
|
||||
if p > 0 {
|
||||
page = p
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// the default mode is none paging
|
||||
return fmtLevelMetric
|
||||
}
|
||||
|
||||
var limit = DefaultPageLimit
|
||||
|
||||
if limitNum != "" {
|
||||
l, err := strconv.Atoi(limitNum)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
} else {
|
||||
if l > 0 {
|
||||
limit = l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the i page: [(page-1) * limit, (page) * limit - 1]
|
||||
start := (page - 1) * limit
|
||||
end := (page)*limit - 1
|
||||
|
||||
for i := 0; i < len(fmtLevelMetric.Results); i++ {
|
||||
// only pageing when result type is `vector` and result status is `success`
|
||||
if fmtLevelMetric.Results[i].Data.ResultType != ResultTypeVector || fmtLevelMetric.Results[i].Status != MetricStatusSuccess {
|
||||
continue
|
||||
}
|
||||
resultLen := len(fmtLevelMetric.Results[i].Data.Result)
|
||||
if start >= resultLen {
|
||||
fmtLevelMetric.Results[i].Data.Result = nil
|
||||
continue
|
||||
}
|
||||
if end >= resultLen {
|
||||
end = resultLen - 1
|
||||
}
|
||||
slice := fmtLevelMetric.Results[i].Data.Result[start : end+1]
|
||||
fmtLevelMetric.Results[i].Data.Result = slice
|
||||
}
|
||||
|
||||
allPage := int(math.Ceil(float64(maxLength) / float64(limit)))
|
||||
|
||||
// add page fields
|
||||
return &struct {
|
||||
*FormatedLevelMetric
|
||||
CurrentPage int `json:"page"`
|
||||
TotalPage int `json:"total_page"`
|
||||
TotalItem int `json:"total_item"`
|
||||
Message string `json:"msg"`
|
||||
}{
|
||||
FormatedLevelMetric: fmtLevelMetric,
|
||||
CurrentPage: page,
|
||||
TotalItem: maxLength,
|
||||
TotalPage: allPage,
|
||||
Message: "paged",
|
||||
}
|
||||
}
|
||||
|
||||
// maybe this function is time consuming
|
||||
func ReformatJson(metric string, metricsName string, needDelParams ...string) *FormatedMetric {
|
||||
var formatMetric FormatedMetric
|
||||
|
||||
err := jsonIter.Unmarshal([]byte(metric), &formatMetric)
|
||||
if err != nil {
|
||||
glog.Errorln("Unmarshal metric json failed", err.Error(), metric)
|
||||
}
|
||||
if formatMetric.MetricName == "" {
|
||||
if metricsName != "" {
|
||||
formatMetric.MetricName = metricsName
|
||||
}
|
||||
}
|
||||
// retrive metrics success
|
||||
if formatMetric.Status == MetricStatusSuccess {
|
||||
result := formatMetric.Data.Result
|
||||
for _, res := range result {
|
||||
metric, exist := res[ResultItemMetric]
|
||||
metricMap, sure := metric.(map[string]interface{})
|
||||
if exist && sure {
|
||||
delete(metricMap, "__name__")
|
||||
}
|
||||
if len(needDelParams) > 0 {
|
||||
for _, p := range needDelParams {
|
||||
delete(metricMap, p)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &formatMetric
|
||||
}
|
||||
|
||||
func ReformatNodeStatusField(nodeMetric *FormatedMetric) *FormatedMetric {
|
||||
metricCount := len(nodeMetric.Data.Result)
|
||||
for i := 0; i < metricCount; i++ {
|
||||
metric, exist := nodeMetric.Data.Result[i][ResultItemMetric]
|
||||
if exist {
|
||||
status, exist := metric.(map[string]interface{})[MetricStatus]
|
||||
if exist {
|
||||
status = UpperFirstLetter(status.(string))
|
||||
metric.(map[string]interface{})[MetricStatus] = status
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodeMetric
|
||||
}
|
||||
|
||||
func UpperFirstLetter(str string) string {
|
||||
for i, ch := range str {
|
||||
return string(unicode.ToUpper(ch)) + str[i+1:]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
285
pkg/models/nodes/nodes.go
Normal file
285
pkg/models/nodes/nodes.go
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 nodes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/apps/v1beta2"
|
||||
"k8s.io/api/core/v1"
|
||||
policy "k8s.io/api/policy/v1beta1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
func DrainNode(nodename string) (err error) {
|
||||
|
||||
k8sclient := client.K8sClient()
|
||||
node, err := k8sclient.CoreV1().Nodes().Get(nodename, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if node.Spec.Unschedulable {
|
||||
return errors.New(errors.Conflict, fmt.Sprintf("node %s have been drained", nodename))
|
||||
}
|
||||
|
||||
data := []byte(" {\"spec\":{\"unschedulable\":true}}")
|
||||
nodestatus, err := k8sclient.CoreV1().Nodes().Patch(nodename, types.StrategicMergePatchType, data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
glog.Info(nodestatus)
|
||||
donech := make(chan bool)
|
||||
errch := make(chan error)
|
||||
go drainEviction(nodename, donech, errch)
|
||||
for {
|
||||
select {
|
||||
case err := <-errch:
|
||||
return err
|
||||
case <-donech:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func drainEviction(nodename string, donech chan bool, errch chan error) {
|
||||
|
||||
k8sclient := client.K8sClient()
|
||||
var options metav1.ListOptions
|
||||
pods := make([]v1.Pod, 0)
|
||||
options.FieldSelector = "spec.nodeName=" + nodename
|
||||
podList, err := k8sclient.CoreV1().Pods("").List(options)
|
||||
if err != nil {
|
||||
glog.Fatal(err)
|
||||
errch <- err
|
||||
}
|
||||
options.FieldSelector = ""
|
||||
daemonsetList, err := k8sclient.AppsV1beta2().DaemonSets("").List(options)
|
||||
|
||||
if err != nil {
|
||||
|
||||
glog.Fatal(err)
|
||||
errch <- err
|
||||
|
||||
}
|
||||
// remove mirror pod static pod
|
||||
if len(podList.Items) > 0 {
|
||||
|
||||
for _, pod := range podList.Items {
|
||||
|
||||
if !containDaemonset(pod, *daemonsetList) {
|
||||
//static or mirror pod
|
||||
if isStaticPod(&pod) || isMirrorPod(&pod) {
|
||||
continue
|
||||
} else {
|
||||
pods = append(pods, pod)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(pods) == 0 {
|
||||
donech <- true
|
||||
} else {
|
||||
|
||||
//create eviction
|
||||
getPodFn := func(namespace, name string) (*v1.Pod, error) {
|
||||
k8sclient := client.K8sClient()
|
||||
return k8sclient.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
|
||||
}
|
||||
evicerr := evictPods(pods, 0, getPodFn)
|
||||
|
||||
if evicerr == nil {
|
||||
donech <- true
|
||||
} else {
|
||||
glog.Fatal(evicerr)
|
||||
errch <- err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getPodSource(pod *v1.Pod) (string, error) {
|
||||
if pod.Annotations != nil {
|
||||
if source, ok := pod.Annotations["kubernetes.io/config.source"]; ok {
|
||||
return source, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("cannot get source of pod %q", pod.UID)
|
||||
}
|
||||
|
||||
func isStaticPod(pod *v1.Pod) bool {
|
||||
source, err := getPodSource(pod)
|
||||
return err == nil && source != "api"
|
||||
}
|
||||
|
||||
func isMirrorPod(pod *v1.Pod) bool {
|
||||
_, ok := pod.Annotations[v1.MirrorPodAnnotationKey]
|
||||
return ok
|
||||
}
|
||||
|
||||
func containDaemonset(pod v1.Pod, daemonsetList v1beta2.DaemonSetList) bool {
|
||||
|
||||
flag := false
|
||||
for _, daemonset := range daemonsetList.Items {
|
||||
|
||||
if strings.Contains(pod.Name, daemonset.Name) {
|
||||
|
||||
flag = true
|
||||
}
|
||||
|
||||
}
|
||||
return flag
|
||||
|
||||
}
|
||||
|
||||
func evictPod(pod v1.Pod, GracePeriodSeconds int) error {
|
||||
|
||||
k8sclient := client.K8sClient()
|
||||
deleteOptions := &metav1.DeleteOptions{}
|
||||
if GracePeriodSeconds >= 0 {
|
||||
gracePeriodSeconds := int64(GracePeriodSeconds)
|
||||
deleteOptions.GracePeriodSeconds = &gracePeriodSeconds
|
||||
}
|
||||
|
||||
var eviction policy.Eviction
|
||||
eviction.Kind = "Eviction"
|
||||
eviction.APIVersion = "policy/v1beta1"
|
||||
eviction.Namespace = pod.Namespace
|
||||
eviction.Name = pod.Name
|
||||
eviction.DeleteOptions = deleteOptions
|
||||
err := k8sclient.CoreV1().Pods(pod.Namespace).Evict(&eviction)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func evictPods(pods []v1.Pod, GracePeriodSeconds int, getPodFn func(namespace, name string) (*v1.Pod, error)) error {
|
||||
doneCh := make(chan bool, len(pods))
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
for _, pod := range pods {
|
||||
go func(pod v1.Pod, doneCh chan bool, errCh chan error) {
|
||||
var err error
|
||||
var count int
|
||||
for {
|
||||
err = evictPod(pod, GracePeriodSeconds)
|
||||
if err == nil {
|
||||
count++
|
||||
if count > 2 {
|
||||
break
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
count = 0
|
||||
doneCh <- true
|
||||
glog.Info(fmt.Sprintf("pod %s evict", pod.Name))
|
||||
return
|
||||
} else if apierrors.IsTooManyRequests(err) {
|
||||
count = 0
|
||||
time.Sleep(5 * time.Second)
|
||||
} else {
|
||||
count = 0
|
||||
errCh <- fmt.Errorf("error when evicting pod %q: %v", pod.Name, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
podArray := []v1.Pod{pod}
|
||||
_, err = waitForDelete(podArray, time.Second, time.Duration(math.MaxInt64), getPodFn)
|
||||
if err == nil {
|
||||
doneCh <- true
|
||||
glog.Info(fmt.Sprintf("pod %s delete", pod.Name))
|
||||
} else {
|
||||
errCh <- fmt.Errorf("error when waiting for pod %q terminating: %v", pod.Name, err)
|
||||
}
|
||||
}(pod, doneCh, errCh)
|
||||
}
|
||||
|
||||
Timeout := 300 * power(10, 9)
|
||||
doneCount := 0
|
||||
// 0 timeout means infinite, we use MaxInt64 to represent it.
|
||||
var globalTimeout time.Duration
|
||||
if Timeout == 0 {
|
||||
globalTimeout = time.Duration(math.MaxInt64)
|
||||
} else {
|
||||
globalTimeout = time.Duration(Timeout)
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-doneCh:
|
||||
doneCount++
|
||||
if doneCount == len(pods) {
|
||||
return nil
|
||||
}
|
||||
case <-time.After(globalTimeout):
|
||||
return fmt.Errorf("drain did not complete within %v", globalTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func waitForDelete(pods []v1.Pod, interval, timeout time.Duration, getPodFn func(string, string) (*v1.Pod, error)) ([]v1.Pod, error) {
|
||||
|
||||
err := wait.PollImmediate(interval, timeout, func() (bool, error) {
|
||||
var pendingPods []v1.Pod
|
||||
for i, pod := range pods {
|
||||
p, err := getPodFn(pod.Namespace, pod.Name)
|
||||
if apierrors.IsNotFound(err) || (p != nil && p.ObjectMeta.UID != pod.ObjectMeta.UID) {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return false, err
|
||||
} else {
|
||||
pendingPods = append(pendingPods, pods[i])
|
||||
}
|
||||
}
|
||||
pods = pendingPods
|
||||
if len(pendingPods) > 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
})
|
||||
return pods, err
|
||||
}
|
||||
|
||||
func power(x int64, n int) int64 {
|
||||
|
||||
var res int64 = 1
|
||||
for n != 0 {
|
||||
res *= x
|
||||
n--
|
||||
}
|
||||
|
||||
return res
|
||||
|
||||
}
|
||||
151
pkg/models/quotas/quotas.go
Normal file
151
pkg/models/quotas/quotas.go
Normal file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 quotas
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
)
|
||||
|
||||
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"
|
||||
jobsKey = "count/jobs.batch"
|
||||
cronJobsKey = "count/cronjobs.batch"
|
||||
)
|
||||
|
||||
var (
|
||||
resourceMap = map[string]string{daemonsetsKey: resources.DaemonSets, deploymentsKey: resources.Deployments,
|
||||
ingressKey: resources.Ingresses, rolesKey: resources.Roles, servicesKey: resources.Services,
|
||||
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
|
||||
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
|
||||
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
|
||||
resouceQuotaLister v12.ResourceQuotaLister
|
||||
)
|
||||
|
||||
type ResourceQuota struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Data v1.ResourceQuotaStatus `json:"data"`
|
||||
}
|
||||
|
||||
func getUsage(namespace, resource string) (int, error) {
|
||||
list, err := resources.ListNamespaceResource(namespace, resource, "", "", false, -1, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return list.TotalCount, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
resouceQuotaLister = informers.SharedInformerFactory().Core().V1().ResourceQuotas().Lister()
|
||||
}
|
||||
|
||||
func GetClusterQuotas() (*ResourceQuota, error) {
|
||||
|
||||
quota := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
||||
|
||||
for k, v := range resourceMap {
|
||||
used, err := getUsage("", v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var quantity resource.Quantity
|
||||
quantity.Set(int64(used))
|
||||
quota.Used[v1.ResourceName(k)] = quantity
|
||||
}
|
||||
|
||||
return &ResourceQuota{Namespace: "\"\"", Data: quota}, nil
|
||||
|
||||
}
|
||||
|
||||
func GetNamespaceQuotas(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, err := getUsage(namespace, v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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 res, usage := range resourceList {
|
||||
tmpUsage, exist := tmpResourceList[res]
|
||||
if !exist {
|
||||
tmpResourceList[res] = usage
|
||||
}
|
||||
if tmpUsage.Cmp(usage) == 1 {
|
||||
tmpResourceList[res] = usage
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func getNamespaceResourceQuota(namespace string) (*v1.ResourceQuotaStatus, error) {
|
||||
quotaList, err := resouceQuotaLister.ResourceQuotas(namespace).List(labels.Everything())
|
||||
if err != nil || len(quotaList) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
quotaStatus := v1.ResourceQuotaStatus{Hard: make(v1.ResourceList), Used: make(v1.ResourceList)}
|
||||
|
||||
for _, quota := range quotaList {
|
||||
updateNamespaceQuota(quotaStatus.Hard, quota.Status.Hard)
|
||||
updateNamespaceQuota(quotaStatus.Used, quota.Status.Used)
|
||||
}
|
||||
|
||||
return "aStatus, nil
|
||||
}
|
||||
67
pkg/models/registries/registries.go
Normal file
67
pkg/models/registries/registries.go
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 registries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/golang/glog"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
type AuthInfo struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
ServerHost string `json:"serverhost"`
|
||||
}
|
||||
|
||||
const loginSuccess = "Login Succeeded"
|
||||
|
||||
func RegistryVerify(authInfo AuthInfo) error {
|
||||
auth := base64.StdEncoding.EncodeToString([]byte(authInfo.Username + ":" + authInfo.Password))
|
||||
ctx := context.Background()
|
||||
cli, err := client.NewEnvClient()
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
config := types.AuthConfig{
|
||||
Username: authInfo.Username,
|
||||
Password: authInfo.Password,
|
||||
Auth: auth,
|
||||
ServerAddress: authInfo.ServerHost,
|
||||
}
|
||||
|
||||
resp, err := cli.RegistryLogin(ctx, config)
|
||||
cli.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.Status == loginSuccess {
|
||||
return nil
|
||||
} else {
|
||||
return errors.New(errors.VerifyFailed, resp.Status)
|
||||
}
|
||||
}
|
||||
121
pkg/models/resources/clusterroles.go
Normal file
121
pkg/models/resources/clusterroles.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/listers/rbac/v1"
|
||||
)
|
||||
|
||||
type clusterRoleSearcher struct {
|
||||
clusterRoleLister v1.ClusterRoleLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRole) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*clusterRoleSearcher) compare(a, b *rbac.ClusterRole, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *clusterRoleSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
clusterRoles, err := s.clusterRoleLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*rbac.ClusterRole, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = clusterRoles
|
||||
} else {
|
||||
for _, item := range clusterRoles {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
126
pkg/models/resources/configmaps.go
Normal file
126
pkg/models/resources/configmaps.go
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type configMapSearcher struct {
|
||||
configMapLister lister.ConfigMapLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*configMapSearcher) match(match map[string]string, item *v1.ConfigMap) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*configMapSearcher) compare(a, b *v1.ConfigMap, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *configMapSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
configMaps, err := s.configMapLister.ConfigMaps(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.ConfigMap, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = configMaps
|
||||
} else {
|
||||
for _, item := range configMaps {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
134
pkg/models/resources/cronjobs.go
Normal file
134
pkg/models/resources/cronjobs.go
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/batch/v2alpha1"
|
||||
|
||||
"k8s.io/api/batch/v2alpha1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type cronJobSearcher struct {
|
||||
cronJobLister lister.CronJobLister
|
||||
}
|
||||
|
||||
func cronJobStatus(item *v2alpha1.CronJob) string {
|
||||
if item.Spec.Suspend != nil && *item.Spec.Suspend {
|
||||
return paused
|
||||
}
|
||||
return running
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*cronJobSearcher) match(match map[string]string, item *v2alpha1.CronJob) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
if cronJobStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v2alpha1.CronJob) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (*cronJobSearcher) compare(a, b *v2alpha1.CronJob, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *cronJobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
cronJobs, err := s.cronJobLister.CronJobs(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v2alpha1.CronJob, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = cronJobs
|
||||
} else {
|
||||
for _, item := range cronJobs {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
137
pkg/models/resources/daemonsets.go
Normal file
137
pkg/models/resources/daemonsets.go
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type daemonSetSearcher struct {
|
||||
daemonSetLister lister.DaemonSetLister
|
||||
}
|
||||
|
||||
func daemonSetStatus(item *v1.DaemonSet) string {
|
||||
if item.Status.NumberAvailable == 0 {
|
||||
return stopped
|
||||
} else if item.Status.DesiredNumberScheduled == item.Status.NumberAvailable {
|
||||
return running
|
||||
} else {
|
||||
return updating
|
||||
}
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
if daemonSetStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*daemonSetSearcher) fuzzy(fuzzy map[string]string, item *v1.DaemonSet) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (*daemonSetSearcher) compare(a, b *v1.DaemonSet, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *daemonSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
daemonSets, err := s.daemonSetLister.DaemonSets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.DaemonSet, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = daemonSets
|
||||
} else {
|
||||
for _, item := range daemonSets {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
141
pkg/models/resources/deployments.go
Normal file
141
pkg/models/resources/deployments.go
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
)
|
||||
|
||||
type deploymentSearcher struct {
|
||||
deploymentLister lister.DeploymentLister
|
||||
}
|
||||
|
||||
func deploymentStatus(item *v1.Deployment) string {
|
||||
if item.Spec.Replicas != nil {
|
||||
if item.Status.ReadyReplicas == 0 && *item.Spec.Replicas == 0 {
|
||||
return stopped
|
||||
} else if item.Status.ReadyReplicas == *item.Spec.Replicas {
|
||||
return running
|
||||
} else {
|
||||
return updating
|
||||
}
|
||||
}
|
||||
return stopped
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
if deploymentStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*deploymentSearcher) fuzzy(fuzzy map[string]string, item *v1.Deployment) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (*deploymentSearcher) compare(a, b *v1.Deployment, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *deploymentSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
deployments, err := s.deploymentLister.Deployments(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.Deployment, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = deployments
|
||||
} else {
|
||||
for _, item := range deployments {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
127
pkg/models/resources/ingresses.go
Normal file
127
pkg/models/resources/ingresses.go
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/extensions/v1beta1"
|
||||
|
||||
extensions "k8s.io/api/extensions/v1beta1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type ingressSearcher struct {
|
||||
ingressLister lister.IngressLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*ingressSearcher) match(match map[string]string, item *extensions.Ingress) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*ingressSearcher) compare(a, b *extensions.Ingress, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ingressSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
ingresses, err := s.ingressLister.Ingresses(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*extensions.Ingress, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = ingresses
|
||||
} else {
|
||||
for _, item := range ingresses {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
156
pkg/models/resources/jobs.go
Normal file
156
pkg/models/resources/jobs.go
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
lister "k8s.io/client-go/listers/batch/v1"
|
||||
|
||||
batchV1 "k8s.io/api/batch/v1"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type jobSearcher struct {
|
||||
jobLister lister.JobLister
|
||||
}
|
||||
|
||||
func jobStatus(item *batchV1.Job) string {
|
||||
status := ""
|
||||
|
||||
for _, condition := range item.Status.Conditions {
|
||||
if condition.Type == batchV1.JobFailed && condition.Status == coreV1.ConditionTrue {
|
||||
status = failed
|
||||
}
|
||||
if condition.Type == batchV1.JobComplete && condition.Status == coreV1.ConditionTrue {
|
||||
status = complete
|
||||
}
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*jobSearcher) match(match map[string]string, item *batchV1.Job) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
if jobStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchV1.Job) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func jobUpdateTime(item *batchV1.Job) time.Time {
|
||||
updateTime := item.CreationTimestamp.Time
|
||||
for _, condition := range item.Status.Conditions {
|
||||
if updateTime.Before(condition.LastProbeTime.Time) {
|
||||
updateTime = condition.LastProbeTime.Time
|
||||
}
|
||||
if updateTime.Before(condition.LastTransitionTime.Time) {
|
||||
updateTime = condition.LastTransitionTime.Time
|
||||
}
|
||||
}
|
||||
return updateTime
|
||||
}
|
||||
|
||||
func (*jobSearcher) compare(a, b *batchV1.Job, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case updateTime:
|
||||
return jobUpdateTime(a).After(jobUpdateTime(b))
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *jobSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
jobs, err := s.jobLister.Jobs(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*batchV1.Job, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = jobs
|
||||
} else {
|
||||
for _, item := range jobs {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
125
pkg/models/resources/namespaces.go
Normal file
125
pkg/models/resources/namespaces.go
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
)
|
||||
|
||||
type namespaceSearcher struct {
|
||||
namespaceLister lister.NamespaceLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *namespaceSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
namespaces, err := s.namespaceLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.Namespace, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = namespaces
|
||||
} else {
|
||||
for _, item := range namespaces {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
125
pkg/models/resources/nodes.go
Normal file
125
pkg/models/resources/nodes.go
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
)
|
||||
|
||||
type nodeSearcher struct {
|
||||
nodeLister lister.NodeLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*nodeSearcher) match(match map[string]string, item *v1.Node) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*nodeSearcher) compare(a, b *v1.Node, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *nodeSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
nodes, err := s.nodeLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.Node, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = nodes
|
||||
} else {
|
||||
for _, item := range nodes {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
126
pkg/models/resources/persistentvolumeclaims.go
Normal file
126
pkg/models/resources/persistentvolumeclaims.go
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type persistentVolumeClaimSearcher struct {
|
||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*persistentVolumeClaimSearcher) compare(a, b *v1.PersistentVolumeClaim, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *persistentVolumeClaimSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
persistentVolumeClaims, err := s.persistentVolumeClaimLister.PersistentVolumeClaims(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.PersistentVolumeClaim, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = persistentVolumeClaims
|
||||
} else {
|
||||
for _, item := range persistentVolumeClaims {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
127
pkg/models/resources/pods.go
Normal file
127
pkg/models/resources/pods.go
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type podSearcher struct {
|
||||
podLister v12.PodLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*podSearcher) compare(a, b *v1.Pod, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *podSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
|
||||
pods, err := s.podLister.Pods(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.Pod, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = pods
|
||||
} else {
|
||||
for _, item := range pods {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
240
pkg/models/resources/resources.go
Normal file
240
pkg/models/resources/resources.go
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
namespacedResources[ConfigMaps] = &configMapSearcher{
|
||||
configMapLister: informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister(),
|
||||
}
|
||||
namespacedResources[CronJobs] = &cronJobSearcher{
|
||||
cronJobLister: informers.SharedInformerFactory().Batch().V2alpha1().CronJobs().Lister(),
|
||||
}
|
||||
namespacedResources[DaemonSets] = &daemonSetSearcher{
|
||||
daemonSetLister: informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister(),
|
||||
}
|
||||
namespacedResources[Deployments] = &deploymentSearcher{
|
||||
deploymentLister: informers.SharedInformerFactory().Apps().V1().Deployments().Lister(),
|
||||
}
|
||||
namespacedResources[Ingresses] = &ingressSearcher{
|
||||
ingressLister: informers.SharedInformerFactory().Extensions().V1beta1().Ingresses().Lister(),
|
||||
}
|
||||
namespacedResources[Jobs] = &jobSearcher{
|
||||
jobLister: informers.SharedInformerFactory().Batch().V1().Jobs().Lister(),
|
||||
}
|
||||
namespacedResources[PersistentVolumeClaims] = &persistentVolumeClaimSearcher{
|
||||
persistentVolumeClaimLister: informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister(),
|
||||
}
|
||||
namespacedResources[Secrets] = &secretSearcher{
|
||||
secretLister: informers.SharedInformerFactory().Core().V1().Secrets().Lister(),
|
||||
}
|
||||
namespacedResources[Services] = &serviceSearcher{
|
||||
serviceLister: informers.SharedInformerFactory().Core().V1().Services().Lister(),
|
||||
}
|
||||
namespacedResources[StatefulSets] = &statefulSetSearcher{
|
||||
statefulSetLister: informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister(),
|
||||
}
|
||||
namespacedResources[Pods] = &podSearcher{
|
||||
podLister: informers.SharedInformerFactory().Core().V1().Pods().Lister(),
|
||||
}
|
||||
namespacedResources[Roles] = &roleSearcher{
|
||||
roleLister: informers.SharedInformerFactory().Rbac().V1().Roles().Lister(),
|
||||
}
|
||||
|
||||
clusterResources[Nodes] = &nodeSearcher{
|
||||
nodeLister: informers.SharedInformerFactory().Core().V1().Nodes().Lister(),
|
||||
}
|
||||
clusterResources[Namespaces] = &namespaceSearcher{
|
||||
namespaceLister: informers.SharedInformerFactory().Core().V1().Namespaces().Lister(),
|
||||
}
|
||||
clusterResources[ClusterRoles] = &clusterRoleSearcher{
|
||||
clusterRoleLister: informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister(),
|
||||
}
|
||||
clusterResources[StorageClasses] = &storageClassesSearcher{
|
||||
storageClassesLister: informers.SharedInformerFactory().Storage().V1().StorageClasses().Lister(),
|
||||
}
|
||||
}
|
||||
|
||||
var namespacedResources = make(map[string]namespacedSearcherInterface)
|
||||
var clusterResources = make(map[string]clusterSearcherInterface)
|
||||
|
||||
type conditions struct {
|
||||
match map[string]string
|
||||
fuzzy map[string]string
|
||||
}
|
||||
|
||||
const (
|
||||
name = "name"
|
||||
label = "label"
|
||||
createTime = "createTime"
|
||||
updateTime = "updateTime"
|
||||
displayName = "displayName"
|
||||
chart = "chart"
|
||||
release = "release"
|
||||
annotation = "annotation"
|
||||
keyword = "keyword"
|
||||
status = "status"
|
||||
running = "running"
|
||||
paused = "paused"
|
||||
updating = "updating"
|
||||
stopped = "stopped"
|
||||
failed = "failed"
|
||||
complete = "complete"
|
||||
app = "app"
|
||||
Deployments = "deployments"
|
||||
DaemonSets = "daemonsets"
|
||||
Roles = "roles"
|
||||
CronJobs = "cronjobs"
|
||||
ConfigMaps = "configmaps"
|
||||
Ingresses = "ingresses"
|
||||
Jobs = "jobs"
|
||||
PersistentVolumeClaims = "persistentvolumeclaims"
|
||||
Pods = "pods"
|
||||
Secrets = "secrets"
|
||||
Services = "services"
|
||||
StatefulSets = "statefulsets"
|
||||
Nodes = "nodes"
|
||||
Namespaces = "namespaces"
|
||||
StorageClasses = "storageclasses"
|
||||
ClusterRoles = "clusterroles"
|
||||
)
|
||||
|
||||
type namespacedSearcherInterface interface {
|
||||
search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||
}
|
||||
type clusterSearcherInterface interface {
|
||||
search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||
}
|
||||
|
||||
func ListNamespaceResource(namespace, resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) {
|
||||
items := make([]interface{}, 0)
|
||||
total := 0
|
||||
var err error
|
||||
|
||||
conditions, err := parseToConditions(conditionStr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []interface{}
|
||||
|
||||
if searcher, ok := namespacedResources[resource]; ok {
|
||||
result, err = searcher.search(namespace, conditions, orderBy, reverse)
|
||||
} else {
|
||||
return nil, errors.New(errors.NotImplement, "not support")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.Internal, err.Error())
|
||||
}
|
||||
|
||||
total = len(result)
|
||||
|
||||
for i, d := range result {
|
||||
if i >= offset && (limit == -1 || len(items) < limit) {
|
||||
items = append(items, d)
|
||||
}
|
||||
}
|
||||
|
||||
return &ResourceList{TotalCount: total, Items: items}, nil
|
||||
}
|
||||
|
||||
func ListClusterResource(resource, conditionStr, orderBy string, reverse bool, limit, offset int) (*ResourceList, error) {
|
||||
items := make([]interface{}, 0)
|
||||
total := 0
|
||||
var err error
|
||||
|
||||
conditions, err := parseToConditions(conditionStr)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []interface{}
|
||||
|
||||
if searcher, ok := clusterResources[resource]; ok {
|
||||
result, err = searcher.search(conditions, orderBy, reverse)
|
||||
} else {
|
||||
return nil, errors.New(errors.NotImplement, "not support")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.New(errors.Internal, err.Error())
|
||||
}
|
||||
|
||||
total = len(result)
|
||||
|
||||
for i, d := range result {
|
||||
if i >= offset && len(items) < limit {
|
||||
items = append(items, d)
|
||||
}
|
||||
}
|
||||
|
||||
return &ResourceList{TotalCount: total, Items: items}, nil
|
||||
}
|
||||
|
||||
func parseToConditions(str string) (*conditions, error) {
|
||||
conditions := &conditions{match: make(map[string]string, 0), fuzzy: make(map[string]string, 0)}
|
||||
|
||||
if str == "" {
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
for _, item := range strings.Split(str, ",") {
|
||||
if strings.Count(item, "=") > 1 || strings.Count(item, "~") > 1 {
|
||||
return nil, errors.New(errors.InvalidArgument, "invalid condition")
|
||||
}
|
||||
if groups := regexp.MustCompile(`(\S+)([=~])(\S+)`).FindStringSubmatch(item); len(groups) == 4 {
|
||||
if groups[2] == "=" {
|
||||
conditions.match[groups[1]] = groups[3]
|
||||
} else {
|
||||
conditions.fuzzy[groups[1]] = groups[3]
|
||||
}
|
||||
} else {
|
||||
return nil, errors.New(errors.InvalidArgument, "invalid condition")
|
||||
}
|
||||
}
|
||||
return conditions, nil
|
||||
}
|
||||
|
||||
type ResourceList struct {
|
||||
TotalCount int `json:"total_count"`
|
||||
Items []interface{} `json:"items"`
|
||||
}
|
||||
|
||||
func searchFuzzy(m map[string]string, key, value string) bool {
|
||||
for k, v := range m {
|
||||
if key == "" {
|
||||
if strings.Contains(k, value) || strings.Contains(v, value) {
|
||||
return true
|
||||
}
|
||||
} else if k == key && strings.Contains(v, value) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
122
pkg/models/resources/roles.go
Normal file
122
pkg/models/resources/roles.go
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
lister "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type roleSearcher struct {
|
||||
roleLister lister.RoleLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*roleSearcher) match(match map[string]string, item *rbac.Role) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*roleSearcher) compare(a, b *rbac.Role, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *roleSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
roles, err := s.roleLister.Roles(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*rbac.Role, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = roles
|
||||
} else {
|
||||
for _, item := range roles {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
130
pkg/models/resources/secrets.go
Normal file
130
pkg/models/resources/secrets.go
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type secretSearcher struct {
|
||||
secretLister lister.SecretLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*secretSearcher) match(match map[string]string, item *v1.Secret) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
case "type":
|
||||
if string(item.Type) != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*secretSearcher) compare(a, b *v1.Secret, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *secretSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
secrets, err := s.secretLister.Secrets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.Secret, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = secrets
|
||||
} else {
|
||||
for _, item := range secrets {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
126
pkg/models/resources/services.go
Normal file
126
pkg/models/resources/services.go
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type serviceSearcher struct {
|
||||
serviceLister lister.ServiceLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*serviceSearcher) match(match map[string]string, item *v1.Service) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*serviceSearcher) compare(a, b *v1.Service, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *serviceSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
services, err := s.serviceLister.Services(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.Service, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = services
|
||||
} else {
|
||||
for _, item := range services {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
140
pkg/models/resources/statefulsets.go
Normal file
140
pkg/models/resources/statefulsets.go
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type statefulSetSearcher struct {
|
||||
statefulSetLister lister.StatefulSetLister
|
||||
}
|
||||
|
||||
func statefulSetStatus(item *v1.StatefulSet) string {
|
||||
if item.Spec.Replicas != nil {
|
||||
if item.Status.ReadyReplicas == 0 && *item.Spec.Replicas == 0 {
|
||||
return stopped
|
||||
} else if item.Status.ReadyReplicas == *item.Spec.Replicas {
|
||||
return running
|
||||
} else {
|
||||
return updating
|
||||
}
|
||||
}
|
||||
return stopped
|
||||
}
|
||||
|
||||
// Exactly match
|
||||
func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
if statefulSetStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*statefulSetSearcher) fuzzy(fuzzy map[string]string, item *v1.StatefulSet) bool {
|
||||
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case app:
|
||||
if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) {
|
||||
return false
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (*statefulSetSearcher) compare(a, b *v1.StatefulSet, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *statefulSetSearcher) search(namespace string, conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
statefulSets, err := s.statefulSetLister.StatefulSets(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.StatefulSet, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = statefulSets
|
||||
} else {
|
||||
for _, item := range statefulSets {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
121
pkg/models/resources/storageclasses.go
Normal file
121
pkg/models/resources/storageclasses.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/storage/v1"
|
||||
)
|
||||
|
||||
type storageClassesSearcher struct {
|
||||
storageClassesLister lister.StorageClassLister
|
||||
}
|
||||
|
||||
// exactly match
|
||||
func (*storageClassesSearcher) match(match map[string]string, item *v1.StorageClass) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fuzzy searchInNamespace
|
||||
func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageClass) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*storageClassesSearcher) compare(a, b *v1.StorageClass, orderBy string) bool {
|
||||
switch orderBy {
|
||||
case createTime:
|
||||
return a.CreationTimestamp.Time.After(b.CreationTimestamp.Time)
|
||||
case name:
|
||||
fallthrough
|
||||
default:
|
||||
return strings.Compare(a.Name, b.Name) <= 0
|
||||
}
|
||||
}
|
||||
|
||||
func (s *storageClassesSearcher) search(conditions *conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
storageClasses, err := s.storageClassesLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.StorageClass, 0)
|
||||
|
||||
if len(conditions.match) == 0 && len(conditions.fuzzy) == 0 {
|
||||
result = storageClasses
|
||||
} else {
|
||||
for _, item := range storageClasses {
|
||||
if s.match(conditions.match, item) && s.fuzzy(conditions.fuzzy, item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if reverse {
|
||||
tmp := i
|
||||
i = j
|
||||
j = tmp
|
||||
}
|
||||
return s.compare(result[i], result[j], orderBy)
|
||||
})
|
||||
|
||||
r := make([]interface{}, 0)
|
||||
for _, i := range result {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
114
pkg/models/revisions/revisions.go
Normal file
114
pkg/models/revisions/revisions.go
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 revisions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/apps/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/apps/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
)
|
||||
|
||||
var (
|
||||
daemonSetLister lister.DaemonSetLister
|
||||
deploymentLister lister.DeploymentLister
|
||||
replicaSetLister lister.ReplicaSetLister
|
||||
statefulSetLister lister.StatefulSetLister
|
||||
controllerRevisionLister lister.ControllerRevisionLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
daemonSetLister = informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister()
|
||||
deploymentLister = informers.SharedInformerFactory().Apps().V1().Deployments().Lister()
|
||||
replicaSetLister = informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister()
|
||||
statefulSetLister = informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister()
|
||||
controllerRevisionLister = informers.SharedInformerFactory().Apps().V1().ControllerRevisions().Lister()
|
||||
}
|
||||
|
||||
func GetDeployRevision(namespace, name, revision string) (*v1.ReplicaSet, error) {
|
||||
deploy, err := deploymentLister.Deployments(namespace).Get(name)
|
||||
if err != nil {
|
||||
glog.Errorf("get deployment %s failed, reason: %s", name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labelMap := deploy.Spec.Template.Labels
|
||||
labelSelector := labels.Set(labelMap).AsSelector()
|
||||
|
||||
rsList, err := replicaSetLister.ReplicaSets(namespace).List(labelSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, rs := range rsList {
|
||||
if rs.Annotations["deployment.kubernetes.io/revision"] == revision {
|
||||
return rs, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision))
|
||||
}
|
||||
|
||||
func GetDaemonSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
||||
|
||||
ds, err := daemonSetLister.DaemonSets(namespace).Get(name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
labels := ds.Spec.Template.Labels
|
||||
|
||||
return getControllerRevision(namespace, name, labels, revisionInt)
|
||||
}
|
||||
|
||||
func GetStatefulSetRevision(namespace, name string, revisionInt int) (*v1.ControllerRevision, error) {
|
||||
|
||||
st, err := statefulSetLister.StatefulSets(namespace).Get(name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return getControllerRevision(namespace, name, st.Spec.Template.Labels, revisionInt)
|
||||
}
|
||||
|
||||
func getControllerRevision(namespace, name string, labelMap map[string]string, revision int) (*v1.ControllerRevision, error) {
|
||||
|
||||
labelSelector := labels.Set(labelMap).AsSelector()
|
||||
|
||||
revisions, err := controllerRevisionLister.ControllerRevisions(namespace).List(labelSelector)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, controllerRevision := range revisions {
|
||||
if controllerRevision.Revision == int64(revision) {
|
||||
return controllerRevision, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("revision not found %v#%v", name, revision))
|
||||
}
|
||||
327
pkg/models/routers/routers.go
Normal file
327
pkg/models/routers/routers.go
Normal file
@@ -0,0 +1,327 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 routers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/errors"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
|
||||
"github.com/golang/glog"
|
||||
coreV1 "k8s.io/api/core/v1"
|
||||
extensionsV1beta1 "k8s.io/api/extensions/v1beta1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
|
||||
"k8s.io/api/rbac/v1"
|
||||
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
)
|
||||
|
||||
var (
|
||||
serviceLister v12.ServiceLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
serviceLister = informers.SharedInformerFactory().Core().V1().Services().Lister()
|
||||
}
|
||||
|
||||
func GetAllRouters() ([]*coreV1.Service, error) {
|
||||
|
||||
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend"})
|
||||
|
||||
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func GetAllRoutersOfUser(username string) ([]*coreV1.Service, error) {
|
||||
allNamespace, namespaces, err := iam.GetUserNamespaces(username, v1.PolicyRule{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"services"},
|
||||
})
|
||||
|
||||
// return by cluster role
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if allNamespace {
|
||||
return GetAllRouters()
|
||||
}
|
||||
|
||||
routers := make([]*coreV1.Service, 0)
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
router, err := GetRouter(namespace)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return routers, err
|
||||
} else if router != nil {
|
||||
routers = append(routers, router)
|
||||
}
|
||||
}
|
||||
|
||||
return routers, nil
|
||||
|
||||
}
|
||||
|
||||
// Get router from a namespace
|
||||
func GetRouter(namespace string) (*coreV1.Service, error) {
|
||||
serviceName := constants.IngressControllerPrefix + namespace
|
||||
|
||||
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend", "project": namespace})
|
||||
|
||||
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
for _, s := range services {
|
||||
if s.Name == serviceName {
|
||||
return s, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New(errors.NotFound, fmt.Sprintf("resources not found %s", serviceName))
|
||||
}
|
||||
|
||||
// Load all resource yamls
|
||||
func LoadYamls() ([]string, error) {
|
||||
|
||||
var yamls []string
|
||||
|
||||
files, err := ioutil.ReadDir(constants.IngressControllerFolder)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if file.IsDir() || !strings.HasSuffix(file.Name(), ".yaml") {
|
||||
continue
|
||||
}
|
||||
content, err := ioutil.ReadFile(constants.IngressControllerFolder + "/" + file.Name())
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
} else {
|
||||
yamls = append(yamls, string(content))
|
||||
}
|
||||
}
|
||||
|
||||
return yamls, nil
|
||||
}
|
||||
|
||||
// Create a ingress controller in a namespace
|
||||
func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) {
|
||||
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
|
||||
yamls, err := LoadYamls()
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
for _, f := range yamls {
|
||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||
obj, _, err := decode([]byte(f), nil, nil)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return router, err
|
||||
}
|
||||
|
||||
switch obj.(type) {
|
||||
case *coreV1.Service:
|
||||
service := obj.(*coreV1.Service)
|
||||
|
||||
service.SetAnnotations(annotations)
|
||||
service.Spec.Type = routerType
|
||||
service.Name = constants.IngressControllerPrefix + namespace
|
||||
|
||||
// Add project selector
|
||||
service.Labels["project"] = namespace
|
||||
|
||||
service.Spec.Selector["project"] = namespace
|
||||
|
||||
service, err := k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Create(service)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
router = service
|
||||
|
||||
case *extensionsV1beta1.Deployment:
|
||||
deployment := obj.(*extensionsV1beta1.Deployment)
|
||||
deployment.Name = constants.IngressControllerPrefix + namespace
|
||||
|
||||
// Add project label
|
||||
deployment.Spec.Selector.MatchLabels["project"] = namespace
|
||||
deployment.Spec.Template.Labels["project"] = namespace
|
||||
|
||||
// Isolate namespace
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--watch-namespace="+namespace)
|
||||
|
||||
// Choose self as master
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--election-id="+deployment.Name)
|
||||
|
||||
if routerType == coreV1.ServiceTypeLoadBalancer {
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--publish-service="+constants.IngressControllerNamespace+"/"+constants.IngressControllerPrefix+namespace)
|
||||
} else {
|
||||
deployment.Spec.Template.Spec.Containers[0].Args = append(deployment.Spec.Template.Spec.Containers[0].Args, "--report-node-internal-ip-address")
|
||||
}
|
||||
|
||||
deployment, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Create(deployment)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
default:
|
||||
//glog.Info("Default resource")
|
||||
}
|
||||
}
|
||||
|
||||
return router, nil
|
||||
}
|
||||
|
||||
// DeleteRouter is used to delete ingress controller related resources in namespace
|
||||
// It will not delete ClusterRole resource cause it maybe used by other controllers
|
||||
func DeleteRouter(namespace string) (*coreV1.Service, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
var err error
|
||||
var router *coreV1.Service
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
// delete controller service
|
||||
serviceName := constants.IngressControllerPrefix + namespace
|
||||
deleteOptions := metaV1.DeleteOptions{}
|
||||
|
||||
listOptions := metaV1.ListOptions{
|
||||
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
||||
FieldSelector: "metadata.name=" + serviceName}
|
||||
|
||||
serviceList, err := k8sClient.CoreV1().Services(constants.IngressControllerNamespace).List(listOptions)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
if len(serviceList.Items) > 0 {
|
||||
router = &serviceList.Items[0]
|
||||
err = k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Delete(serviceName, &deleteOptions)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// delete controller deployment
|
||||
deploymentName := constants.IngressControllerPrefix + namespace
|
||||
|
||||
listOptions = metaV1.ListOptions{
|
||||
LabelSelector: "app=kubesphere,component=ks-router,tier=backend,project=" + namespace,
|
||||
}
|
||||
deployments, err := k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).List(listOptions)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
if len(deployments.Items) > 0 {
|
||||
err = k8sClient.ExtensionsV1beta1().Deployments(constants.IngressControllerNamespace).Delete(deploymentName, &deleteOptions)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return router, nil
|
||||
}
|
||||
|
||||
// Update Ingress Controller Service, change type from NodePort to Loadbalancer or vice versa.
|
||||
func UpdateRouter(namespace string, routerType coreV1.ServiceType, annotations map[string]string) (*coreV1.Service, error) {
|
||||
k8sClient := client.K8sClient()
|
||||
|
||||
var router *coreV1.Service
|
||||
|
||||
router, err := GetRouter(namespace)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return router, nil
|
||||
}
|
||||
|
||||
if router == nil {
|
||||
glog.Error("Trying to update a non-existed router")
|
||||
return nil, errors.New(errors.Internal, "router not created yet")
|
||||
}
|
||||
|
||||
// from LoadBalancer to NodePort, or vice-versa
|
||||
if router.Spec.Type != routerType {
|
||||
router, err = DeleteRouter(namespace)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
router, err = CreateRouter(namespace, routerType, annotations)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
|
||||
return router, err
|
||||
|
||||
} else {
|
||||
router.SetAnnotations(annotations)
|
||||
|
||||
router, err = k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Update(router)
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return router, err
|
||||
}
|
||||
}
|
||||
|
||||
return router, nil
|
||||
}
|
||||
57
pkg/models/status/status.go
Normal file
57
pkg/models/status/status.go
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 status
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
)
|
||||
|
||||
type workLoadStatus struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Count map[string]int `json:"data"`
|
||||
Items map[string]interface{} `json:"items,omitempty"`
|
||||
}
|
||||
|
||||
func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
||||
res := workLoadStatus{Count: make(map[string]int), Namespace: namespace, Items: make(map[string]interface{})}
|
||||
var notReadyList *resources.ResourceList
|
||||
var err error
|
||||
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} {
|
||||
notReadyStatus := "updating"
|
||||
if resource == resources.PersistentVolumeClaims {
|
||||
notReadyStatus = "pending"
|
||||
}
|
||||
|
||||
notReadyList, err = resources.ListNamespaceResource(namespace, resource, fmt.Sprintf("status=%s", notReadyStatus), "", false, -1, 0)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res.Count[resource] = notReadyList.TotalCount
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
func GetClusterResourceStatus() (*workLoadStatus, error) {
|
||||
|
||||
return GetNamespacesResourceStatus("")
|
||||
}
|
||||
112
pkg/models/storage/storage.go
Normal file
112
pkg/models/storage/storage.go
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 storage
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
storageV1 "k8s.io/api/storage/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
lister "k8s.io/client-go/listers/core/v1"
|
||||
lister2 "k8s.io/client-go/listers/storage/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
)
|
||||
|
||||
type ScMetrics struct {
|
||||
Capacity string `json:"capacity,omitempty"`
|
||||
Usage string `json:"usage,omitempty"`
|
||||
PvcNumber string `json:"pvcNumber"`
|
||||
}
|
||||
|
||||
var (
|
||||
persistentVolumeClaimLister lister.PersistentVolumeClaimLister
|
||||
persistentVolumeLister lister.PersistentVolumeLister
|
||||
sotrageClassesLister lister2.StorageClassLister
|
||||
)
|
||||
|
||||
func init() {
|
||||
persistentVolumeClaimLister = informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister()
|
||||
persistentVolumeLister = informers.SharedInformerFactory().Core().V1().PersistentVolumes().Lister()
|
||||
}
|
||||
|
||||
func GetPvcListBySc(scName string) ([]*v1.PersistentVolumeClaim, error) {
|
||||
all, err := persistentVolumeClaimLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1.PersistentVolumeClaim, 0)
|
||||
|
||||
for _, item := range all {
|
||||
if item.Spec.StorageClassName != nil {
|
||||
if *item.Spec.StorageClassName == scName {
|
||||
result = append(result, item.DeepCopy())
|
||||
}
|
||||
} else if item.GetAnnotations()[v1.BetaStorageClassAnnotation] == scName {
|
||||
result = append(result, item.DeepCopy())
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Get info of metrics
|
||||
func GetScMetrics(scName string) (*ScMetrics, error) {
|
||||
pvList, err := persistentVolumeLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Get PVC
|
||||
pvcList, err := GetPvcListBySc(scName)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get storage usage
|
||||
// Gathering usage of a specific StorageClass
|
||||
var total resource.Quantity
|
||||
for _, volume := range pvList {
|
||||
if volume.Spec.StorageClassName != scName {
|
||||
continue
|
||||
}
|
||||
total.Add(volume.Spec.Capacity[v1.ResourceStorage])
|
||||
}
|
||||
usage := total.String()
|
||||
|
||||
// Get PVC number
|
||||
pvcNum := len(pvcList)
|
||||
|
||||
return &ScMetrics{Usage: usage, PvcNumber: strconv.Itoa(pvcNum)}, nil
|
||||
}
|
||||
|
||||
// Get SC item list
|
||||
func GetScList() ([]*storageV1.StorageClass, error) {
|
||||
|
||||
// Get StorageClass list
|
||||
scList, err := sotrageClassesLister.List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return scList, nil
|
||||
}
|
||||
57
pkg/models/storage/volumes.go
Normal file
57
pkg/models/storage/volumes.go
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 storage
|
||||
|
||||
import (
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
)
|
||||
|
||||
var podLister v12.PodLister
|
||||
|
||||
func init() {
|
||||
podLister = informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
}
|
||||
|
||||
// List pods of a specific persistent volume claims
|
||||
func GetPodListByPvc(pvc string, ns string) (res []*v1.Pod, err error) {
|
||||
podList, err := podLister.Pods(ns).List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, pod := range podList {
|
||||
if IsPvcInPod(pod, pvc) == true {
|
||||
res = append(res, pod.DeepCopy())
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Check if the persistent volume claim is related to the pod
|
||||
func IsPvcInPod(pod *v1.Pod, pvcName string) bool {
|
||||
for _, v := range pod.Spec.Volumes {
|
||||
if v.VolumeSource.PersistentVolumeClaim != nil &&
|
||||
v.VolumeSource.PersistentVolumeClaim.ClaimName == pvcName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
27
pkg/models/types.go
Normal file
27
pkg/models/types.go
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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
|
||||
|
||||
type MessageResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type PageableResponse struct {
|
||||
Items []interface{} `json:"items"`
|
||||
TotalCount int `json:"total_count"`
|
||||
}
|
||||
79
pkg/models/workloads/jobs.go
Normal file
79
pkg/models/workloads/jobs.go
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 workloads
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/batch/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
)
|
||||
|
||||
const retryTimes = 3
|
||||
|
||||
func JobReRun(namespace, jobName string) error {
|
||||
k8sClient := client.K8sClient()
|
||||
job, err := k8sClient.BatchV1().Jobs(namespace).Get(jobName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newJob := *job
|
||||
newJob.ResourceVersion = ""
|
||||
newJob.Status = v1.JobStatus{}
|
||||
newJob.ObjectMeta.UID = ""
|
||||
newJob.Annotations["revisions"] = strings.Replace(job.Annotations["revisions"], "running", "unfinished", -1)
|
||||
|
||||
delete(newJob.Spec.Selector.MatchLabels, "controller-uid")
|
||||
delete(newJob.Spec.Template.ObjectMeta.Labels, "controller-uid")
|
||||
|
||||
err = deleteJob(namespace, jobName)
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("failed to rerun job %s, reason: %s", jobName, err)
|
||||
return fmt.Errorf("failed to rerun job %s", jobName)
|
||||
}
|
||||
|
||||
for i := 0; i < retryTimes; i++ {
|
||||
_, err = k8sClient.BatchV1().Jobs(namespace).Create(&newJob)
|
||||
if err != nil {
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("failed to rerun job %s, reason: %s", jobName, err)
|
||||
return fmt.Errorf("failed to rerun job %s", jobName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteJob(namespace, job string) error {
|
||||
k8sClient := client.K8sClient()
|
||||
deletePolicy := metav1.DeletePropagationBackground
|
||||
err := k8sClient.BatchV1().Jobs(namespace).Delete(job, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
return err
|
||||
}
|
||||
63
pkg/models/workspaces/types.go
Normal file
63
pkg/models/workspaces/types.go
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 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 workspaces
|
||||
|
||||
import "time"
|
||||
|
||||
type Workspace struct {
|
||||
Group `json:",inline"`
|
||||
Admin string `json:"admin,omitempty"`
|
||||
Namespaces []string `json:"namespaces"`
|
||||
DevopsProjects []string `json:"devops_projects"`
|
||||
}
|
||||
|
||||
type UserInvite struct {
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
Path string `json:"path"`
|
||||
Name string `json:"name"`
|
||||
Gid string `json:"gid"`
|
||||
Members []string `json:"members"`
|
||||
Logo string `json:"logo"`
|
||||
Creator string `json:"creator"`
|
||||
CreateTime string `json:"create_time"`
|
||||
ChildGroups []string `json:"child_groups,omitempty"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (g Group) GetCreateTime() (time.Time, error) {
|
||||
return time.Parse("2006-01-02T15:04:05Z", g.CreateTime)
|
||||
}
|
||||
|
||||
type WorkspaceDPBinding struct {
|
||||
Workspace string `gorm:"primary_key"`
|
||||
DevOpsProject string `gorm:"primary_key"`
|
||||
}
|
||||
|
||||
type DevopsProject struct {
|
||||
ProjectId *string `json:"project_id,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Creator string `json:"creator"`
|
||||
CreateTime *time.Time `json:"create_time,omitempty"`
|
||||
Status *string `json:"status"`
|
||||
Visibility *string `json:"visibility,omitempty"`
|
||||
}
|
||||
1379
pkg/models/workspaces/workspaces.go
Normal file
1379
pkg/models/workspaces/workspaces.go
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user