@@ -90,7 +90,12 @@ func DescribeWorkspace(req *restful.Request, resp *restful.Response) {
|
||||
result, err := tenant.DescribeWorkspace(username, workspaceName)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
glog.Errorf("describe workspace failed: %+v", err)
|
||||
if k8serr.IsNotFound(err) {
|
||||
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||
} else {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -189,10 +189,13 @@ func (r *ReconcileNamespace) checkAndCreateRoles(namespace *corev1.Namespace) er
|
||||
log.Info("Creating default role", "namespace", namespace.Name, "role", role.Name)
|
||||
err = r.Create(context.TODO(), role)
|
||||
if err != nil {
|
||||
log.Info("Creating default role failed", "namespace", namespace.Name, "role", role.Name)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Info("Get default role failed", "namespace", namespace.Name, "role", role.Name)
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -352,11 +352,11 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi
|
||||
}
|
||||
switch orderBy {
|
||||
case "username":
|
||||
fallthrough
|
||||
case "createTime":
|
||||
return users[i].CreateTime.Before(users[j].CreateTime)
|
||||
default:
|
||||
return strings.Compare(users[i].Username, users[j].Username) <= 0
|
||||
case "createTime":
|
||||
fallthrough
|
||||
default:
|
||||
return users[i].CreateTime.Before(users[j].CreateTime)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ package metrics
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"runtime/debug"
|
||||
@@ -1009,11 +1010,11 @@ func GetAllWorkspacesStatistics() *FormatedLevelMetric {
|
||||
}()
|
||||
|
||||
go func() {
|
||||
actNums, errAct := workspaces.GetAllAccountNums()
|
||||
result, errAct := kubesphere.Client().ListUsers()
|
||||
if errAct != nil {
|
||||
glog.Errorln(errAct.Error())
|
||||
}
|
||||
accountResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllAccountCount, WorkspaceResourceKindAccount, actNums, errAct)
|
||||
accountResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllAccountCount, WorkspaceResourceKindAccount, result.TotalCount, errAct)
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
|
||||
@@ -39,9 +39,9 @@ func (*cronJobSearcher) get(namespace, name string) (interface{}, error) {
|
||||
|
||||
func cronJobStatus(item *v1beta1.CronJob) string {
|
||||
if item.Spec.Suspend != nil && *item.Spec.Suspend {
|
||||
return paused
|
||||
return StatusPaused
|
||||
}
|
||||
return running
|
||||
return StatusRunning
|
||||
}
|
||||
|
||||
// Exactly Match
|
||||
@@ -53,7 +53,7 @@ func (*cronJobSearcher) match(match map[string]string, item *v1beta1.CronJob) bo
|
||||
if !sliceutil.HasString(names, item.Name) {
|
||||
return false
|
||||
}
|
||||
case status:
|
||||
case Status:
|
||||
if cronJobStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -38,11 +38,11 @@ func (*daemonSetSearcher) get(namespace, name string) (interface{}, error) {
|
||||
|
||||
func daemonSetStatus(item *v1.DaemonSet) string {
|
||||
if item.Status.NumberAvailable == 0 {
|
||||
return stopped
|
||||
return StatusStopped
|
||||
} else if item.Status.DesiredNumberScheduled == item.Status.NumberAvailable {
|
||||
return running
|
||||
return StatusRunning
|
||||
} else {
|
||||
return updating
|
||||
return StatusUpdating
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ func daemonSetStatus(item *v1.DaemonSet) string {
|
||||
func (*daemonSetSearcher) match(match map[string]string, item *v1.DaemonSet) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
case Status:
|
||||
if daemonSetStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -40,21 +40,21 @@ func (*deploymentSearcher) get(namespace, name string) (interface{}, error) {
|
||||
func deploymentStatus(item *v1.Deployment) string {
|
||||
if item.Spec.Replicas != nil {
|
||||
if item.Status.ReadyReplicas == 0 && *item.Spec.Replicas == 0 {
|
||||
return stopped
|
||||
return StatusStopped
|
||||
} else if item.Status.ReadyReplicas == *item.Spec.Replicas {
|
||||
return running
|
||||
return StatusRunning
|
||||
} else {
|
||||
return updating
|
||||
return StatusUpdating
|
||||
}
|
||||
}
|
||||
return stopped
|
||||
return StatusStopped
|
||||
}
|
||||
|
||||
// Exactly Match
|
||||
func (*deploymentSearcher) match(match map[string]string, item *v1.Deployment) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
case Status:
|
||||
if deploymentStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
|
||||
74
pkg/models/resources/extraannotations.go
Normal file
74
pkg/models/resources/extraannotations.go
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
|
||||
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 (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
)
|
||||
|
||||
type extraAnnotationInjector struct {
|
||||
}
|
||||
|
||||
func (i extraAnnotationInjector) addExtraAnnotations(item interface{}) interface{} {
|
||||
|
||||
switch item.(type) {
|
||||
case *v1.PersistentVolumeClaim:
|
||||
return i.injectPersistentVolumeClaim(item.(*v1.PersistentVolumeClaim))
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func (i extraAnnotationInjector) injectPersistentVolumeClaim(item *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim {
|
||||
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
pods, err := podLister.Pods(item.Namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Errorf("inject annotation failed %+v", err)
|
||||
return item
|
||||
}
|
||||
|
||||
item = item.DeepCopy()
|
||||
|
||||
if item.Annotations == nil {
|
||||
item.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
if isPvcInUse(pods, item.Name) {
|
||||
item.Annotations["kubesphere.io/in-use"] = "true"
|
||||
} else {
|
||||
item.Annotations["kubesphere.io/in-use"] = "false"
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
func isPvcInUse(pods []*v1.Pod, pvcName string) bool {
|
||||
for _, pod := range pods {
|
||||
volumes := pod.Spec.Volumes
|
||||
for _, volume := range volumes {
|
||||
pvc := volume.PersistentVolumeClaim
|
||||
if pvc != nil && pvc.ClaimName == pvcName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import (
|
||||
"time"
|
||||
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
@@ -40,15 +39,13 @@ func (*jobSearcher) get(namespace, name string) (interface{}, error) {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
status := StatusFailed
|
||||
if item.Status.Active > 0 {
|
||||
status = StatusRunning
|
||||
} else if item.Status.Failed > 0 {
|
||||
status = StatusFailed
|
||||
} else if item.Status.Succeeded > 0 {
|
||||
status = StatusComplete
|
||||
}
|
||||
return status
|
||||
}
|
||||
@@ -57,7 +54,7 @@ func jobStatus(item *batchv1.Job) string {
|
||||
func (*jobSearcher) match(match map[string]string, item *batchv1.Job) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case status:
|
||||
case Status:
|
||||
if jobStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -36,6 +36,18 @@ func (*persistentVolumeClaimSearcher) get(namespace, name string) (interface{},
|
||||
return informers.SharedInformerFactory().Core().V1().PersistentVolumeClaims().Lister().PersistentVolumeClaims(namespace).Get(name)
|
||||
}
|
||||
|
||||
func pvcStatus(item *v1.PersistentVolumeClaim) string {
|
||||
status := StatusPending
|
||||
if item.Status.Phase == v1.ClaimPending {
|
||||
status = StatusPending
|
||||
} else if item.Status.Phase == v1.ClaimBound {
|
||||
status = StatusBound
|
||||
} else if item.Status.Phase == v1.ClaimLost {
|
||||
status = StatusLost
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.PersistentVolumeClaim) bool {
|
||||
for k, v := range match {
|
||||
@@ -45,6 +57,11 @@ func (*persistentVolumeClaimSearcher) match(match map[string]string, item *v1.Pe
|
||||
if !sliceutil.HasString(names, item.Name) {
|
||||
return false
|
||||
}
|
||||
case Status:
|
||||
statuses := strings.Split(v, "|")
|
||||
if !sliceutil.HasString(statuses, pvcStatus(item)) {
|
||||
return false
|
||||
}
|
||||
case Keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
|
||||
@@ -51,6 +51,7 @@ func init() {
|
||||
}
|
||||
|
||||
var (
|
||||
injector = extraAnnotationInjector{}
|
||||
resources = make(map[string]resourceSearchInterface)
|
||||
clusterResources = []string{Nodes, Workspaces, Namespaces, ClusterRoles, StorageClasses, S2iBuilderTemplates}
|
||||
)
|
||||
@@ -67,17 +68,20 @@ const (
|
||||
release = "release"
|
||||
annotation = "annotation"
|
||||
Keyword = "keyword"
|
||||
status = "status"
|
||||
Status = "status"
|
||||
includeCronJob = "includeCronJob"
|
||||
cronJobKind = "CronJob"
|
||||
s2iRunKind = "S2iRun"
|
||||
includeS2iRun = "includeS2iRun"
|
||||
running = "running"
|
||||
paused = "paused"
|
||||
updating = "updating"
|
||||
stopped = "stopped"
|
||||
failed = "failed"
|
||||
complete = "complete"
|
||||
StatusRunning = "running"
|
||||
StatusPaused = "paused"
|
||||
StatusPending = "pending"
|
||||
StatusUpdating = "updating"
|
||||
StatusStopped = "stopped"
|
||||
StatusFailed = "failed"
|
||||
StatusBound = "bound"
|
||||
StatusLost = "lost"
|
||||
StatusComplete = "complete"
|
||||
app = "app"
|
||||
Deployments = "deployments"
|
||||
DaemonSets = "daemonsets"
|
||||
@@ -142,9 +146,9 @@ func ListResources(namespace, resource string, conditions *params.Conditions, or
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, d := range result {
|
||||
for i, item := range result {
|
||||
if i >= offset && (limit == -1 || len(items) < limit) {
|
||||
items = append(items, d)
|
||||
items = append(items, injector.addExtraAnnotations(item))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ func (*s2iRunSearcher) match(match map[string]string, item *v1alpha1.S2iRun) boo
|
||||
if !sliceutil.HasString(names, item.Name) {
|
||||
return false
|
||||
}
|
||||
case status:
|
||||
case Status:
|
||||
if string(item.Status.RunState) != v {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -39,14 +39,14 @@ func (*statefulSetSearcher) get(namespace, name string) (interface{}, error) {
|
||||
func statefulSetStatus(item *v1.StatefulSet) string {
|
||||
if item.Spec.Replicas != nil {
|
||||
if item.Status.ReadyReplicas == 0 && *item.Spec.Replicas == 0 {
|
||||
return stopped
|
||||
return StatusStopped
|
||||
} else if item.Status.ReadyReplicas == *item.Spec.Replicas {
|
||||
return running
|
||||
return StatusRunning
|
||||
} else {
|
||||
return updating
|
||||
return StatusUpdating
|
||||
}
|
||||
}
|
||||
return stopped
|
||||
return StatusStopped
|
||||
}
|
||||
|
||||
// Exactly Match
|
||||
@@ -62,7 +62,7 @@ func (*statefulSetSearcher) match(match map[string]string, item *v1.StatefulSet)
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
case status:
|
||||
case Status:
|
||||
if statefulSetStatus(item) != v {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -18,8 +18,10 @@
|
||||
package status
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||
)
|
||||
@@ -34,15 +36,22 @@ func GetNamespacesResourceStatus(namespace string) (*workLoadStatus, error) {
|
||||
res := workLoadStatus{Count: make(map[string]int), Namespace: namespace, Items: make(map[string]interface{})}
|
||||
var notReadyList *models.PageableResponse
|
||||
var err error
|
||||
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims} {
|
||||
notReadyStatus := "updating"
|
||||
if resource == resources.PersistentVolumeClaims {
|
||||
notReadyStatus = "pending"
|
||||
for _, resource := range []string{resources.Deployments, resources.StatefulSets, resources.DaemonSets, resources.PersistentVolumeClaims, resources.Jobs} {
|
||||
var notReadyStatus string
|
||||
|
||||
switch resource {
|
||||
case resources.PersistentVolumeClaims:
|
||||
notReadyStatus = strings.Join([]string{resources.StatusPending, resources.StatusLost}, "|")
|
||||
case resources.Jobs:
|
||||
notReadyStatus = resources.StatusFailed
|
||||
default:
|
||||
notReadyStatus = resources.StatusUpdating
|
||||
}
|
||||
|
||||
notReadyList, err = resources.ListResources(namespace, resource, ¶ms.Conditions{Match: map[string]string{"status": notReadyStatus}}, "", false, -1, 0)
|
||||
notReadyList, err = resources.ListResources(namespace, resource, ¶ms.Conditions{Match: map[string]string{resources.Status: notReadyStatus}}, "", false, -1, 0)
|
||||
|
||||
if err != nil {
|
||||
glog.Errorf("list resources failed: %+v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -249,11 +249,3 @@ func GetAllDevOpsProjectsNums() (int, error) {
|
||||
}
|
||||
return len(devOpsProjects), nil
|
||||
}
|
||||
|
||||
func GetAllAccountNums() (int, error) {
|
||||
users, err := iam.ListUsers(¶ms.Conditions{}, "", false, 1, 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return users.TotalCount, nil
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ type Interface interface {
|
||||
UpdateGroup(group *models.Group) (*models.Group, error)
|
||||
DescribeGroup(name string) (*models.Group, error)
|
||||
DeleteGroup(name string) error
|
||||
ListUsers() (*models.PageableResponse, error)
|
||||
}
|
||||
|
||||
type client struct {
|
||||
|
||||
Reference in New Issue
Block a user