refactor iam api

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
zryfish
2019-03-17 17:46:00 +08:00
committed by hongming
1728 changed files with 345354 additions and 61115 deletions

View File

@@ -0,0 +1,537 @@
/*
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 applications
import (
"encoding/json"
"fmt"
"github.com/golang/glog"
"io/ioutil"
v12 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1"
"k8s.io/api/extensions/v1beta1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/params"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"net/http"
"strconv"
"strings"
"time"
)
var (
OpenPitrixProxyToken string
OpenPitrixServer string
)
const (
unknown = "-"
deploySuffix = "-Deployment"
daemonSuffix = "-DaemonSet"
stateSuffix = "-StatefulSet"
)
type Application struct {
Name string `json:"name"`
RepoName string `json:"repoName"`
Runtime string `json:"namespace"`
RuntimeId string `json:"runtime_id"`
Version string `json:"version"`
VersionId string `json:"version_id"`
Status string `json:"status"`
UpdateTime time.Time `json:"updateTime"`
CreateTime time.Time `json:"createTime"`
App string `json:"app"`
AppId string `json:"app_id"`
Description string `json:"description,omitempty"`
WorkLoads *workLoads `json:"workloads,omitempty"`
Services []v1.Service `json:"services,omitempty"`
Ingresses []v1beta1.Ingress `json:"ingresses,omitempty"`
ClusterID string `json:"cluster_id"`
}
type clusterRole struct {
ClusterID string `json:"cluster_id"`
Role string `json:"role"`
}
type cluster struct {
ClusterID string `json:"cluster_id"`
Name string `json:"name"`
AppID string `json:"app_id"`
VersionID string `json:"version_id"`
Status string `json:"status"`
UpdateTime time.Time `json:"status_time"`
CreateTime time.Time `json:"create_time"`
RunTimeId string `json:"runtime_id"`
Description string `json:"description"`
ClusterRoleSets []clusterRole `json:"cluster_role_set"`
}
type clusters struct {
Total int `json:"total_count"`
Clusters []cluster `json:"cluster_set"`
}
type versionList struct {
Total int `json:"total_count"`
Versions []version `json:"app_version_set"`
}
type version struct {
Name string `json:"name"`
VersionID string `json:"version_id"`
}
type runtime struct {
RuntimeID string `json:"runtime_id"`
Zone string `json:"zone"`
}
type runtimeList struct {
Total int `json:"total_count"`
Runtimes []runtime `json:"runtime_set"`
}
type app struct {
AppId string `json:"app_id"`
Name string `json:"name"`
ChartName string `json:"chart_name"`
RepoId string `json:"repo_id"`
}
type repo struct {
RepoId string `json:"repo_id"`
Name string `json:"name"`
Url string `json:"url"`
}
type workLoads struct {
Deployments []v12.Deployment `json:"deployments,omitempty"`
Statefulsets []v12.StatefulSet `json:"statefulsets,omitempty"`
Daemonsets []v12.DaemonSet `json:"daemonsets,omitempty"`
}
type appList struct {
Total int `json:"total_count"`
Apps []app `json:"app_set"`
}
type repoList struct {
Total int `json:"total_count"`
Repos []repo `json:"repo_set"`
}
func GetAppInfo(appId string) (string, string, string, error) {
url := fmt.Sprintf("%s/v1/apps?app_id=%s", OpenPitrixServer, appId)
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Error(err)
return unknown, unknown, unknown, err
}
var apps appList
err = json.Unmarshal(resp, &apps)
if err != nil {
glog.Error(err)
return unknown, unknown, unknown, err
}
if len(apps.Apps) == 0 {
return unknown, unknown, unknown, err
}
return apps.Apps[0].ChartName, apps.Apps[0].RepoId, apps.Apps[0].AppId, nil
}
func GetRepo(repoId string) (string, error) {
url := fmt.Sprintf("%s/v1/repos?repo_id=%s", OpenPitrixServer, repoId)
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Error(err)
return unknown, err
}
var repos repoList
err = json.Unmarshal(resp, &repos)
if err != nil {
glog.Error(err)
return unknown, err
}
if len(repos.Repos) == 0 {
return unknown, err
}
return repos.Repos[0].Name, nil
}
func GetVersion(versionId string) (string, error) {
versionUrl := fmt.Sprintf("%s/v1/app_versions?version_id=%s", OpenPitrixServer, versionId)
resp, err := makeHttpRequest("GET", versionUrl, "")
if err != nil {
glog.Error(err)
return unknown, err
}
var versions versionList
err = json.Unmarshal(resp, &versions)
if err != nil {
glog.Error(err)
return unknown, err
}
if len(versions.Versions) == 0 {
return unknown, nil
}
return versions.Versions[0].Name, nil
}
func GetRuntime(runtimeId string) (string, error) {
versionUrl := fmt.Sprintf("%s/v1/runtimes?runtime_id=%s", OpenPitrixServer, runtimeId)
resp, err := makeHttpRequest("GET", versionUrl, "")
if err != nil {
glog.Error(err)
return unknown, err
}
var runtimes runtimeList
err = json.Unmarshal(resp, &runtimes)
if err != nil {
glog.Error(err)
return unknown, err
}
if len(runtimes.Runtimes) == 0 {
return unknown, nil
}
return runtimes.Runtimes[0].Zone, nil
}
func GetWorkLoads(namespace string, clusterRoles []clusterRole) (*workLoads, error) {
var works workLoads
for _, clusterRole := range clusterRoles {
workLoadName := clusterRole.Role
if len(workLoadName) > 0 {
if strings.HasSuffix(workLoadName, deploySuffix) {
name := strings.Split(workLoadName, deploySuffix)[0]
item, err := informers.SharedInformerFactory().Apps().V1().Deployments().Lister().Deployments(namespace).Get(name)
if err != nil {
return nil, err
}
works.Deployments = append(works.Deployments, *item)
continue
}
if strings.HasSuffix(workLoadName, daemonSuffix) {
name := strings.Split(workLoadName, daemonSuffix)[0]
item, err := informers.SharedInformerFactory().Apps().V1().DaemonSets().Lister().DaemonSets(namespace).Get(name)
if err != nil {
return nil, err
}
works.Daemonsets = append(works.Daemonsets, *item)
continue
}
if strings.HasSuffix(workLoadName, stateSuffix) {
name := strings.Split(workLoadName, stateSuffix)[0]
item, err := informers.SharedInformerFactory().Apps().V1().StatefulSets().Lister().StatefulSets(namespace).Get(name)
if err != nil {
return nil, err
}
works.Statefulsets = append(works.Statefulsets, *item)
continue
}
}
}
return &works, nil
}
func getLabels(namespace string, workloads *workLoads) *[]map[string]string {
k8sClient := k8s.Client()
var workloadLables []map[string]string
if workloads == nil {
return nil
}
for _, workload := range workloads.Deployments {
deploy, err := k8sClient.AppsV1().Deployments(namespace).Get(workload.Name, metav1.GetOptions{})
if errors.IsNotFound(err) {
continue
}
workloadLables = append(workloadLables, deploy.Labels)
}
for _, workload := range workloads.Daemonsets {
daemonset, err := k8sClient.AppsV1().DaemonSets(namespace).Get(workload.Name, metav1.GetOptions{})
if errors.IsNotFound(err) {
continue
}
workloadLables = append(workloadLables, daemonset.Labels)
}
for _, workload := range workloads.Statefulsets {
statefulset, err := k8sClient.AppsV1().StatefulSets(namespace).Get(workload.Name, metav1.GetOptions{})
if errors.IsNotFound(err) {
continue
}
workloadLables = append(workloadLables, statefulset.Labels)
}
return &workloadLables
}
func isExist(svcs []v1.Service, svc v1.Service) bool {
for _, item := range svcs {
if item.Name == svc.Name && item.Namespace == svc.Namespace {
return true
}
}
return false
}
func getSvcs(namespace string, workLoadLabels *[]map[string]string) []v1.Service {
if len(*workLoadLabels) == 0 {
return nil
}
k8sClient := k8s.Client()
var services []v1.Service
for _, label := range *workLoadLabels {
labelSelector := labels.Set(label).AsSelector().String()
svcs, err := k8sClient.CoreV1().Services(namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
if err != nil {
glog.Errorf("get app's svc failed, reason: %v", err)
}
for _, item := range svcs.Items {
if !isExist(services, item) {
services = append(services, item)
}
}
}
return services
}
func getIng(namespace string, services []v1.Service) []v1beta1.Ingress {
if services == nil {
return nil
}
var ings []v1beta1.Ingress
for _, svc := range services {
result, err := resources.ListNamespaceResource(namespace, "ingress", &params.Conditions{Fuzzy: map[string]string{"serviceName": svc.Name}}, "", false, -1, 0)
if err != nil {
glog.Error(err)
return nil
}
glog.Error(result)
for _, i := range result.Items {
ingress := i.(*v1beta1.Ingress)
exist := false
var tmpRules []v1beta1.IngressRule
for _, rule := range ingress.Spec.Rules {
for _, p := range rule.HTTP.Paths {
if p.Backend.ServiceName == svc.Name {
exist = true
tmpRules = append(tmpRules, rule)
}
}
}
if exist {
ing := v1beta1.Ingress{}
ing.Name = ingress.Name
ing.Spec.Rules = tmpRules
ings = append(ings, ing)
}
}
}
return ings
}
func ListApplication(runtimeId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) {
if strings.HasSuffix(OpenPitrixServer, "/") {
OpenPitrixServer = strings.TrimSuffix(OpenPitrixServer, "/")
}
defaultStatus := "status=active&status=stopped&status=pending&status=ceased"
url := fmt.Sprintf("%s/v1/clusters?limit=%s&offset=%s", OpenPitrixServer, strconv.Itoa(limit), strconv.Itoa(offset))
if len(conditions.Fuzzy["name"]) > 0 {
url = fmt.Sprintf("%s&search_word=%s", url, conditions.Fuzzy["name"])
}
if len(conditions.Match["status"]) > 0 {
url = fmt.Sprintf("%s&status=%s", url, conditions.Match["status"])
} else {
url = fmt.Sprintf("%s&%s", url, defaultStatus)
}
if len(runtimeId) > 0 {
url = fmt.Sprintf("%s&runtime_id=%s", url, runtimeId)
}
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Errorf("request %s failed, reason: %s", url, err)
return nil, err
}
var clusterList clusters
err = json.Unmarshal(resp, &clusterList)
if err != nil {
return nil, err
}
result := models.PageableResponse{TotalCount: clusterList.Total}
result.Items = make([]interface{}, 0)
for _, item := range clusterList.Clusters {
var app Application
app.Name = item.Name
app.ClusterID = item.ClusterID
app.UpdateTime = item.UpdateTime
app.Status = item.Status
versionInfo, _ := GetVersion(item.VersionID)
app.Version = versionInfo
app.VersionId = item.VersionID
runtimeInfo, _ := GetRuntime(item.RunTimeId)
app.Runtime = runtimeInfo
app.RuntimeId = item.RunTimeId
appInfo, _, appId, _ := GetAppInfo(item.AppID)
app.App = appInfo
app.AppId = appId
app.Description = item.Description
result.Items = append(result.Items, app)
}
return &result, nil
}
func GetApp(clusterId string) (*Application, error) {
if strings.HasSuffix(OpenPitrixServer, "/") {
OpenPitrixServer = strings.TrimSuffix(OpenPitrixServer, "/")
}
url := fmt.Sprintf("%s/v1/clusters?cluster_id=%s", OpenPitrixServer, clusterId)
resp, err := makeHttpRequest("GET", url, "")
if err != nil {
glog.Error(err)
return nil, err
}
var clusterList clusters
err = json.Unmarshal(resp, &clusterList)
if err != nil {
glog.Error(err)
return nil, err
}
if len(clusterList.Clusters) == 0 {
return nil, fmt.Errorf("NotFound, clusterId:%s", clusterId)
}
item := clusterList.Clusters[0]
var app Application
app.Name = item.Name
app.ClusterID = item.ClusterID
app.UpdateTime = item.UpdateTime
app.CreateTime = item.CreateTime
app.Status = item.Status
versionInfo, _ := GetVersion(item.VersionID)
app.Version = versionInfo
app.VersionId = item.VersionID
runtimeInfo, _ := GetRuntime(item.RunTimeId)
app.Runtime = runtimeInfo
app.RuntimeId = item.RunTimeId
appInfo, repoId, appId, _ := GetAppInfo(item.AppID)
app.App = appInfo
app.AppId = appId
app.Description = item.Description
app.RepoName, _ = GetRepo(repoId)
workloads, err := GetWorkLoads(app.Runtime, item.ClusterRoleSets)
if err != nil {
glog.Error(err)
return nil, err
}
app.WorkLoads = workloads
workloadLabels := getLabels(app.Runtime, app.WorkLoads)
app.Services = getSvcs(app.Runtime, workloadLabels)
app.Ingresses = getIng(app.Runtime, app.Services)
return &app, nil
}
func makeHttpRequest(method, url, data string) ([]byte, error) {
var req *http.Request
var err error
if method == "GET" {
req, err = http.NewRequest(method, url, nil)
} else {
req, err = http.NewRequest(method, url, strings.NewReader(data))
}
req.Header.Add("Authorization", OpenPitrixProxyToken)
if err != nil {
glog.Error(err)
return nil, err
}
httpClient := &http.Client{}
resp, err := httpClient.Do(req)
if err != nil {
err := fmt.Errorf("Request to %s failed, method: %s, reason: %s ", url, method, err)
glog.Error(err)
return nil, err
}
body, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
if resp.StatusCode >= http.StatusBadRequest {
err = fmt.Errorf(string(body))
}
return body, err
}

View File

@@ -21,6 +21,7 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/golang/glog"
"io/ioutil"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
@@ -174,7 +175,7 @@ func GetRoles(username string, namespace string) ([]*v1.Role, error) {
func GetClusterRoles(username string) ([]*v1.ClusterRole, error) {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.SelectorFromSet(labels.Set{"": ""}))
if err != nil {
return nil, err
@@ -204,7 +205,7 @@ func GetClusterRoles(username string) ([]*v1.ClusterRole, error) {
roles = append(roles, role)
break
} else if apierrors.IsNotFound(err) {
log.Println(err)
glog.Warningln(err)
break
} else {
return nil, err
@@ -572,8 +573,10 @@ func GetRoleSimpleRules(roles []*v1.Role, namespace string) (map[string][]models
return rulesMapping, nil
}
//
func CreateClusterRoleBinding(username string, clusterRoleName string) error {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
_, err := clusterRoleLister.Get(clusterRoleName)
if err != nil {

View File

@@ -18,19 +18,13 @@
package iam
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"k8s.io/api/rbac/v1"
"k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/constants"
kserr "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
)
@@ -75,27 +69,18 @@ func GetUsers(names []string) ([]models.User, error) {
return make([]models.User, 0), nil
}
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?name=%s", constants.AccountAPIServer, strings.Join(names, ",")))
conn, err := ldap.Client()
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.Parse(data)
}
err = json.Unmarshal(data, &users)
if err != nil {
return nil, err
for _, name := range names {
user, err := UserDetail(name, conn)
if err != nil {
return nil, err
}
users = append(users, *user)
}
return users, nil
@@ -103,32 +88,19 @@ func GetUsers(names []string) ([]models.User, error) {
func GetUser(name string) (*models.User, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users/%s", constants.AccountAPIServer, name))
conn, err := ldap.Client()
if err != nil {
return nil, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
user, err := UserDetail(name, conn)
if err != nil {
return nil, err
}
if result.StatusCode > 200 {
return nil, kserr.Parse(data)
}
var user models.User
err = json.Unmarshal(data, &user)
if err != nil {
return nil, err
}
return &user, nil
return user, nil
}
func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespace bool, namespaces []string, err error) {

View File

@@ -24,7 +24,6 @@ import (
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/redis"
"os"
"regexp"
"strconv"
"strings"
@@ -42,27 +41,18 @@ import (
jwtutils "kubesphere.io/kubesphere/pkg/utils/jwt"
)
const (
envAdminEmail = "ADMIN_EMAIL"
envAdminPWD = "ADMIN_PWD"
)
var (
counter Counter
AdminEmail = "admin@kubesphere.io"
AdminPWD = "passw0rd"
counter Counter
adminEmail string
adminPassword string
tokenExpireTime time.Duration
)
func init() {
if env := os.Getenv(envAdminEmail); env != "" {
AdminEmail = env
}
if env := os.Getenv(envAdminPWD); env != "" {
AdminPWD = env
}
}
func Init(email, password string, t time.Duration) error {
adminEmail = email
adminPassword = password
tokenExpireTime = t
func DatabaseInit() error {
conn, err := ldapclient.Client()
if err != nil {
@@ -96,13 +86,16 @@ func checkAndCreateDefaultGroup(conn ldap.Client) error {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
err = createGroupsBaseDN(conn)
if err != nil {
return fmt.Errorf("GroupBaseDN %s create failed: %s\n", ldapclient.GroupSearchBase, err)
}
}
if err != nil {
return fmt.Errorf("GroupBaseDN %s not exist: %s\n", ldapclient.GroupSearchBase, err)
return fmt.Errorf("iam database init failed: %s\n", err)
}
if len(groups.Entries) == 0 {
if groups == nil || len(groups.Entries) == 0 {
_, err = CreateGroup(models.Group{Path: constants.SystemWorkspace, Name: constants.SystemWorkspace, Creator: constants.AdminUserName, Description: "system workspace"})
if err != nil {
@@ -127,21 +120,24 @@ func checkAndCreateDefaultUser(conn ldap.Client) error {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
err = createUserBaseDN(conn)
}
if err != nil {
return fmt.Errorf("UserBaseDN %s not exist: %s\n", ldapclient.UserSearchBase, err)
}
if len(users.Entries) == 0 {
err := CreateUser(models.User{Username: constants.AdminUserName, Email: AdminEmail, Password: AdminPWD, Description: "Administrator account that was always created by default."})
if err != nil {
return fmt.Errorf("admin create failed: %s\n", err)
return fmt.Errorf("UserBaseDN %s create failed: %s\n", ldapclient.UserSearchBase, err)
}
}
counter = NewCounter(len(users.Entries))
if err != nil {
return fmt.Errorf("iam database init failed: %s\n", err)
}
if users == nil || len(users.Entries) == 0 {
counter = NewCounter(0)
err := CreateUser(models.User{Username: constants.AdminUserName, Email: adminEmail, Password: adminPassword, Description: "Administrator account that was always created by default."})
if err != nil {
return fmt.Errorf("admin create failed: %s\n", err)
}
} else {
counter = NewCounter(len(users.Entries))
}
return nil
}
@@ -200,8 +196,6 @@ func Login(username string, password string, ip string) (string, error) {
email := result.Entries[0].GetAttributeValue("mail")
dn := result.Entries[0].DN
user := models.User{Username: uid, Email: email}
// bind as the user to verify their password
err = conn.Bind(dn, password)
@@ -209,25 +203,29 @@ func Login(username string, password string, ip string) (string, error) {
return "", err
}
if ip != "" {
redisClient := redis.Client()
redisClient.RPush(fmt.Sprintf("kubesphere:users:%s:login-log", uid), fmt.Sprintf("%s,%s", time.Now().UTC().Format("2006-01-02T15:04:05Z"), ip))
redisClient.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", uid), -10, -1)
}
claims := jwt.MapClaims{}
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
claims["username"] = user.Username
claims["email"] = user.Email
claims["exp"] = time.Now().Add(tokenExpireTime).Unix()
claims["username"] = uid
claims["email"] = email
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
uToken, _ := token.SignedString(jwtutils.Secret)
loginLog(uid, ip)
return uToken, nil
}
func loginLog(uid, ip string) {
if ip != "" {
redisClient := redis.Client()
redisClient.RPush(fmt.Sprintf("kubesphere:users:%s:login-log", uid), fmt.Sprintf("%s,%s", time.Now().UTC().Format("2006-01-02T15:04:05Z"), ip))
redisClient.LTrim(fmt.Sprintf("kubesphere:users:%s:login-log", uid), -10, -1)
}
}
func UserList(limit int, offset int) (int, []models.User, error) {
conn, err := ldapclient.Client()
@@ -668,7 +666,7 @@ func CreateUser(user models.User) error {
}
if len(result.Entries) > 0 {
return errors.New("username or email already exists")
return ldap.NewError(ldap.LDAPResultEntryAlreadyExists, fmt.Errorf("username or email already exists"))
}
maxUid, err := getMaxUid(conn)

View File

@@ -732,7 +732,7 @@ func MonitorAllWorkspacesStatistics() *FormatedLevelMetric {
wg.Add(4)
go func() {
orgNums, errOrg := workspaces.Count()
orgNums, errOrg := workspaces.WorkspaceCount()
if errOrg != nil {
glog.Errorln(errOrg.Error())
}

View File

@@ -34,8 +34,6 @@ const (
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"
@@ -47,18 +45,26 @@ const (
var (
resourceMap = map[string]string{daemonsetsKey: resources.DaemonSets, deploymentsKey: resources.Deployments,
ingressKey: resources.Ingresses, rolesKey: resources.Roles, servicesKey: resources.Services,
ingressKey: resources.Ingresses, servicesKey: resources.Services,
statefulsetsKey: resources.StatefulSets, persistentvolumeclaimsKey: resources.PersistentVolumeClaims, podsKey: resources.Pods,
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses, clusterRolesKey: resources.ClusterRoles,
namespaceKey: resources.Namespaces, storageClassesKey: resources.StorageClasses,
jobsKey: resources.Jobs, cronJobsKey: resources.CronJobs}
)
func getUsage(namespace, resource string) (int, error) {
list, err := resources.ListNamespaceResource(namespace, resource, &params.Conditions{}, "", false, -1, 0)
var result *models.PageableResponse
var err error
if resource == resources.Namespaces || resource == resources.StorageClasses {
result, err = resources.ListClusterResource(resource, &params.Conditions{}, "", false, 1, 0)
} else {
result, err = resources.ListNamespaceResource(namespace, resource, &params.Conditions{}, "", false, 1, 0)
}
if err != nil {
return 0, err
}
return list.TotalCount, nil
return result.TotalCount, nil
}
func GetClusterQuotas() (*models.ResourceQuota, error) {

View File

@@ -18,6 +18,7 @@
package resources
import (
v12 "k8s.io/api/apps/v1"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params"
"sort"
@@ -30,16 +31,149 @@ import (
type podSearcher struct {
}
func podBelongTo(item *v1.Pod, kind string, name string) bool {
if strings.EqualFold(kind, "Deployment") {
if podBelongToDeployment(item, name) {
return true
}
} else if strings.EqualFold(kind, "ReplicaSet") {
if podBelongToReplicaSet(item, name) {
return true
}
} else if strings.EqualFold(kind, "DaemonSet") {
if podBelongToDaemonSet(item, name) {
return true
}
} else if strings.EqualFold(kind, "StatefulSet") {
if podBelongToStatefulSet(item, name) {
return true
}
} else if strings.EqualFold(kind, "Job") {
if podBelongToJob(item, name) {
return true
}
}
return false
}
func replicaSetBelongToDeployment(replicaSet *v12.ReplicaSet, name string) bool {
for _, owner := range replicaSet.OwnerReferences {
if owner.Kind == "Deployment" && owner.Name == name {
return true
}
}
return false
}
func podBelongToDaemonSet(item *v1.Pod, name string) bool {
for _, owner := range item.OwnerReferences {
if owner.Kind == "DaemonSet" && owner.Name == name {
return true
}
}
return false
}
func podBelongToJob(item *v1.Pod, name string) bool {
for _, owner := range item.OwnerReferences {
if owner.Kind == "Job" && owner.Name == name {
return true
}
}
return false
}
func podBelongToReplicaSet(item *v1.Pod, name string) bool {
for _, owner := range item.OwnerReferences {
if owner.Kind == "ReplicaSet" && owner.Name == name {
return true
}
}
return false
}
func podBelongToStatefulSet(item *v1.Pod, name string) bool {
replicas, err := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister().ReplicaSets(item.Namespace).List(labels.Everything())
if err != nil {
return false
}
for _, r := range replicas {
if replicaSetBelongToDeployment(r, name) {
return podBelongToReplicaSet(item, r.Name)
}
}
return false
}
func podBelongToDeployment(item *v1.Pod, name string) bool {
replicas, err := informers.SharedInformerFactory().Apps().V1().ReplicaSets().Lister().ReplicaSets(item.Namespace).List(labels.Everything())
if err != nil {
return false
}
for _, r := range replicas {
if replicaSetBelongToDeployment(r, name) {
return podBelongToReplicaSet(item, r.Name)
}
}
return false
}
func podBindPVC(item *v1.Pod, pvcName string) bool {
for _, v := range item.Spec.Volumes {
if v.VolumeSource.PersistentVolumeClaim != nil &&
v.VolumeSource.PersistentVolumeClaim.ClaimName == pvcName {
return true
}
}
return false
}
func podBelongToService(item *v1.Pod, serviceName string) bool {
service, err := informers.SharedInformerFactory().Core().V1().Services().Lister().Services(item.Namespace).Get(serviceName)
if err != nil {
return false
}
for k, v := range service.Spec.Selector {
if item.Labels[k] != v {
return false
}
}
return true
}
// exactly Match
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
for k, v := range match {
switch k {
case "ownerKind":
fallthrough
case "ownerName":
kind := match["ownerKind"]
name := match["ownerName"]
if !podBelongTo(item, kind, name) {
return false
}
case "nodeName":
if item.Spec.NodeName != v {
return false
}
case "pvcName":
if !podBindPVC(item, v) {
return false
}
case "serviceName":
if !podBelongToService(item, v) {
return false
}
case name:
if item.Name != v && item.Labels[displayName] != v {
return false
}
default:
return false
if item.Labels[k] != v {
return false
}
}
}
return true

View File

@@ -131,6 +131,8 @@ func ListClusterResource(resource string, conditions *params.Conditions, orderBy
if searcher, ok := clusterResources[resource]; ok {
result, err = searcher.search(conditions, orderBy, reverse)
} else if searcher, ok := namespacedResources[resource]; ok {
result, err = searcher.search("", conditions, orderBy, reverse)
} else {
return nil, fmt.Errorf("not support")
}

View File

@@ -0,0 +1,7 @@
package metrics
import "github.com/emicklei/go-restful"
func GetAppMetrics(request *restful.Request, response *restful.Response) {
}

View File

@@ -23,6 +23,7 @@ import (
"fmt"
"io/ioutil"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
"net/http"
@@ -40,7 +41,6 @@ import (
"errors"
"regexp"
"github.com/emicklei/go-restful"
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -56,7 +56,6 @@ import (
func UnBindDevopsProject(workspace string, devops string) error {
db := mysql.Client()
defer db.Close()
return db.Delete(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
}
@@ -306,7 +305,6 @@ func Namespaces(workspaceName string) ([]*core.Namespace, error) {
func BindingDevopsProject(workspace string, devops string) error {
db := mysql.Client()
defer db.Close()
return db.Create(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
}
@@ -332,27 +330,11 @@ func Delete(workspace *models.Workspace) error {
return err
}
req, err := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/%s", constants.AccountAPIServer, workspace.Name), nil)
err = iam.DeleteGroup(workspace.Name)
if err != nil {
return err
}
result, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return err
}
if result.StatusCode > 200 {
return kserr.Parse(data)
}
return nil
}
@@ -401,34 +383,13 @@ func workspaceRoleRelease(workspace string) error {
func Create(workspace *models.Workspace) (*models.Workspace, error) {
data, err := json.Marshal(workspace)
group, err := iam.CreateGroup(workspace.Group)
if err != nil {
return nil, err
}
result, err := http.Post(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups", constants.AccountAPIServer), restful.MIME_JSON, bytes.NewReader(data))
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.Parse(data)
}
var created models.Workspace
err = json.Unmarshal(data, &created)
if err != nil {
return nil, err
created := models.Workspace{
Group: *group,
}
created.Members = make([]string, 0)
@@ -446,78 +407,35 @@ func Create(workspace *models.Workspace) (*models.Workspace, error) {
func Edit(workspace *models.Workspace) (*models.Workspace, error) {
data, err := json.Marshal(workspace)
group, err := iam.UpdateGroup(&workspace.Group)
if err != nil {
return nil, err
}
req, err := http.NewRequest(http.MethodPut, fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/%s", constants.AccountAPIServer, workspace.Name), bytes.NewReader(data))
req.Header.Set("Content-Type", "application/json")
workspace.Group = *group
if err != nil {
return nil, err
}
result, err := http.DefaultClient.Do(req)
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.Parse(data)
}
var edited models.Workspace
err = json.Unmarshal(data, &edited)
if err != nil {
return nil, err
}
return &edited, nil
return workspace, nil
}
func Detail(name string) (*models.Workspace, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/%s", constants.AccountAPIServer, name))
conn, err := ldap.Client()
if err != nil {
return nil, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
defer conn.Close()
if err != nil {
return nil, err
}
if result.StatusCode > 200 {
return nil, kserr.Parse(data)
}
var group models.Group
err = json.Unmarshal(data, &group)
group, err := iam.GroupDetail(name, conn)
if err != nil {
return nil, err
}
db := mysql.Client()
defer db.Close()
workspace, err := convertGroupToWorkspace(db, group)
workspace, err := convertGroupToWorkspace(db, *group)
if err != nil {
return nil, err
@@ -570,45 +488,33 @@ func ListWorkspaceByUser(username string, keyword string) ([]*models.Workspace,
func fetch(names []string) ([]*models.Workspace, error) {
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups", constants.AccountAPIServer)
if names != nil {
if len(names) == 0 {
return make([]*models.Workspace, 0), nil
} else {
url = url + "?path=" + strings.Join(names, ",")
if names != nil && len(names) == 0 {
return make([]*models.Workspace, 0), nil
}
var groups []models.Group
var err error
if names == nil {
groups, err = iam.ChildList("")
if err != nil {
return nil, err
}
} else {
conn, err := ldap.Client()
if err != nil {
return nil, err
}
defer conn.Close()
for _, name := range names {
group, err := iam.GroupDetail(name, conn)
if err != nil {
return nil, err
}
groups = append(groups, *group)
}
}
result, err := http.Get(url)
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.Parse(data)
}
var groups []models.Group
err = json.Unmarshal(data, &groups)
if err != nil {
return nil, err
}
db := mysql.Client()
defer db.Close()
workspaces := make([]*models.Workspace, 0)
for _, group := range groups {
workspace, err := convertGroupToWorkspace(db, group)
@@ -624,7 +530,6 @@ func fetch(names []string) ([]*models.Workspace, error) {
func ListDevopsProjectsByUser(username string, workspace string, keyword string, orderBy string, reverse bool, limit int, offset int) (int, []models.DevopsProject, error) {
db := mysql.Client()
defer db.Close()
var workspaceDOPBindings []models.WorkspaceDPBinding
@@ -850,43 +755,6 @@ func Roles(workspace *models.Workspace) ([]*v1.ClusterRole, error) {
return roles, nil
}
func GetWorkspaceMembers(workspace string, keyword string) ([]models.User, error) {
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/workspaces/%s/members", constants.AccountAPIServer, workspace)
if keyword != "" {
url = url + "?keyword=" + keyword
}
result, err := http.Get(url)
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.Parse(data)
}
var users []models.User
err = json.Unmarshal(data, &users)
if err != nil {
return nil, err
}
return users, nil
}
func WorkspaceRoleInit(workspace *models.Workspace) error {
k8sClient := k8s.Client()
@@ -1222,7 +1090,6 @@ func CreateWorkspaceRoleBinding(workspace *models.Workspace, username string, ro
func GetDevOpsProjects(workspaceName string) ([]string, error) {
db := mysql.Client()
defer db.Close()
var workspaceDOPBindings []models.WorkspaceDPBinding
@@ -1266,42 +1133,15 @@ func WorkspaceNamespaces(workspaceName string) ([]string, error) {
return namespaces, nil
}
func Count() (int, error) {
func WorkspaceCount() (int, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/count", constants.AccountAPIServer))
workspaces, err := iam.ChildList("")
if err != nil {
return 0, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return 0, err
}
if result.StatusCode > 200 {
return 0, kserr.Parse(data)
}
var count map[string]json.Number
err = json.Unmarshal(data, &count)
if err != nil {
return 0, err
}
value := count["total_count"]
v, err := value.Int64()
if err != nil {
return 0, err
}
return int(v), nil
return len(workspaces), nil
}
func GetAllProjectNums() (int, error) {
@@ -1315,7 +1155,6 @@ func GetAllProjectNums() (int, error) {
func GetAllDevOpsProjectsNums() (int, error) {
db := mysql.Client()
defer db.Close()
var count int
if err := db.Model(&models.WorkspaceDPBinding{}).Count(&count).Error; err != nil {
@@ -1325,35 +1164,11 @@ func GetAllDevOpsProjectsNums() (int, error) {
}
func GetAllAccountNums() (int, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users", constants.AccountAPIServer))
totalCount, _, err := iam.UserList(1, 0)
if err != nil {
return 0, err
}
defer result.Body.Close()
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return 0, err
}
if result.StatusCode > 200 {
return 0, kserr.Parse(data)
}
var count map[string]json.Number
err = json.Unmarshal(data, &count)
if err != nil {
return 0, err
}
value := count["total_count"]
v, err := value.Int64()
if err != nil {
return 0, err
}
return int(v), nil
return totalCount, nil
}