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