Merge remote-tracking branch 'origin/master'
This commit is contained in:
9
.gitignore
vendored
9
.gitignore
vendored
@@ -11,8 +11,15 @@
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
.idea
|
||||
# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA
|
||||
.idea/
|
||||
*.iml
|
||||
bin/
|
||||
|
||||
# Vscode files
|
||||
.vscode/
|
||||
|
||||
tmp/
|
||||
|
||||
# OSX trash
|
||||
.DS_Store
|
||||
|
||||
@@ -17,11 +17,11 @@ limitations under the License.
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/spf13/pflag"
|
||||
"kubesphere.io/kubesphere/pkg/app"
|
||||
"kubesphere.io/kubesphere/pkg/logs"
|
||||
"kubesphere.io/kubesphere/pkg/options"
|
||||
"kubesphere.io/kubesphere/pkg/version"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
223
pkg/apis/v1alpha/iam/iam_handler.go
Normal file
223
pkg/apis/v1alpha/iam/iam_handler.go
Normal file
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
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 iam
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/filter/route"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"net/http"
|
||||
"strings"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
func Register(ws *restful.WebService) {
|
||||
//roles
|
||||
ws.Route(ws.GET("/users/{username}/roles").To(userRolesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
//rules define
|
||||
ws.Route(ws.GET("/roles/rules").To(roleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
ws.Route(ws.GET("/clusterroles/rules").To(clusterRoleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
//user->rules
|
||||
ws.Route(ws.GET("/rules").To(usersRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
ws.Route(ws.GET("/users/{username}/rules").To(userRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
//role->rules
|
||||
ws.Route(ws.GET("/clusterroles/{name}/rules").To(clusterRoleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
ws.Route(ws.GET("/namespace/{namespace}/roles/{name}/rules").To(roleRulesHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
//role->users
|
||||
ws.Route(ws.GET("/namespaces/{namespace}/roles/{name}/users").To(roleUsersHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
ws.Route(ws.GET("/clusterroles/{name}/users").To(clusterRoleUsersHandler).Filter(route.RouteLogging)).Produces(restful.MIME_JSON)
|
||||
}
|
||||
|
||||
// username -> roles
|
||||
func userRolesHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
username := req.PathParameter("username")
|
||||
|
||||
roles, err := models.GetRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
clusterRoles, err := models.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
roleList := roleList{}
|
||||
roleList.Roles = roles
|
||||
roleList.ClusterRoles = clusterRoles
|
||||
|
||||
resp.WriteEntity(roleList)
|
||||
}
|
||||
|
||||
// namespaces + role name -> users
|
||||
func roleUsersHandler(req *restful.Request, resp *restful.Response) {
|
||||
name := req.PathParameter("name")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
roleBindings, err := models.GetRoleBindings(namespace, name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
users := make([]string, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind {
|
||||
users = append(users, subject.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(users)
|
||||
}
|
||||
|
||||
// cluster role name -> users
|
||||
func clusterRoleUsersHandler(req *restful.Request, resp *restful.Response) {
|
||||
name := req.PathParameter("name")
|
||||
|
||||
roleBindings, err := models.GetClusterRoleBindings(name)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
users := make([]string, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind {
|
||||
users = append(users, subject.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(users)
|
||||
}
|
||||
|
||||
// username -> rules
|
||||
func usersRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
users := strings.Split(req.QueryParameter("users"), ",")
|
||||
|
||||
usersRules := make(map[string]userRuleList, 0)
|
||||
|
||||
for _, username := range users {
|
||||
_, contains := usersRules[username]
|
||||
if username != "" && !contains {
|
||||
|
||||
userRuleList := userRuleList{}
|
||||
|
||||
clusterRules, err := getUserClusterRules(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
rules, err := getUserRules(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
userRuleList.ClusterRules = clusterRules
|
||||
userRuleList.Rules = rules
|
||||
|
||||
usersRules[username] = userRuleList
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(usersRules)
|
||||
}
|
||||
|
||||
// username -> rules
|
||||
func userRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
username := req.PathParameter("username")
|
||||
|
||||
userRuleList := userRuleList{}
|
||||
|
||||
clusterRules, err := getUserClusterRules(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
rules, err := getUserRules(username)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
userRuleList.ClusterRules = clusterRules
|
||||
userRuleList.Rules = rules
|
||||
|
||||
resp.WriteEntity(userRuleList)
|
||||
}
|
||||
|
||||
// cluster role name -> rules
|
||||
func clusterRoleRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
name := req.PathParameter("name")
|
||||
|
||||
var rules []rule
|
||||
|
||||
if name == "" {
|
||||
rules = clusterRoleRuleGroup
|
||||
} else {
|
||||
var err error
|
||||
rules, err = getClusterRoleRules(name)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
|
||||
// role name -> rules
|
||||
func roleRulesHandler(req *restful.Request, resp *restful.Response) {
|
||||
name := req.PathParameter("name")
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
var rules []rule
|
||||
|
||||
if namespace == "" && name == "" {
|
||||
rules = roleRuleGroup
|
||||
} else {
|
||||
var err error
|
||||
rules, err = getRoleRules(namespace, name)
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
resp.WriteEntity(rules)
|
||||
}
|
||||
436
pkg/apis/v1alpha/iam/policy.go
Normal file
436
pkg/apis/v1alpha/iam/policy.go
Normal file
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
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 iam
|
||||
|
||||
import (
|
||||
"k8s.io/api/rbac/v1"
|
||||
)
|
||||
|
||||
type roleList struct {
|
||||
ClusterRoles []v1.ClusterRole `json:"clusterRoles" protobuf:"bytes,2,rep,name=clusterRoles"`
|
||||
Roles []v1.Role `json:"roles" protobuf:"bytes,2,rep,name=roles"`
|
||||
}
|
||||
|
||||
type action struct {
|
||||
Name string `json:"name"`
|
||||
Rules []v1.PolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
Name string `json:"name"`
|
||||
Actions []action `json:"actions"`
|
||||
}
|
||||
|
||||
type userRuleList struct {
|
||||
ClusterRules []rule `json:"clusterRules"`
|
||||
Rules map[string][]rule `json:"rules"`
|
||||
}
|
||||
|
||||
// TODO design all frontend-facing rules
|
||||
var (
|
||||
clusterRoleRuleGroup = []rule{projectsManagement, userManagement, roleManagement, registryManagement,
|
||||
volumeManagement, storageclassManagement, nodeManagement, appCatalogManagement, appManagement}
|
||||
|
||||
roleRuleGroup = []rule{deploymentManagement, projectManagement, statefulsetManagement, daemonsetManagement,
|
||||
serviceManagement, routeManagement, pvcManagement}
|
||||
|
||||
projectsManagement = rule{
|
||||
Name: "projectsManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"namespaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"namespaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete", "deletecollection"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"namespaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
userManagement = rule{
|
||||
Name: "userManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"rolebindings", "clusterrolebindings"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete", "deletecollection"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
roleManagement = rule{
|
||||
Name: "roleManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"roles", "clusterroles"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"roles", "clusterroles"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"roles", "clusterroles"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete", "deletecollection"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"roles", "clusterroles"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "roleBinding",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create", "delete", "deletecollection"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"rolebindings", "clusterrolebindings"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
nodeManagement = rule{
|
||||
Name: "nodeManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"nodes"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
volumeManagement = rule{
|
||||
Name: "volumeManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"persistentvolumes"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
storageclassManagement = rule{
|
||||
Name: "storageclassManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"storage.k8s.io"},
|
||||
Resources: []string{"storageclasses"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
registryManagement = rule{
|
||||
Name: "registryManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"extend.kubesphere.io"},
|
||||
Resources: []string{
|
||||
"registries",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
appCatalogManagement = rule{
|
||||
Name: "appCatalogManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"extend.kubesphere.io"},
|
||||
Resources: []string{"appcatalog"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
appManagement = rule{
|
||||
Name: "appManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"extend.kubesphere.io"},
|
||||
Resources: []string{"apps"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
statefulsetManagement = rule{
|
||||
Name: "statefulsetManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"apps"},
|
||||
Resources: []string{"statefulsets"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
daemonsetManagement = rule{
|
||||
Name: "daemonsetManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
Resources: []string{"daemonsets"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
serviceManagement = rule{
|
||||
Name: "serviceManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"services"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
routeManagement = rule{
|
||||
Name: "routeManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"extensions"},
|
||||
Resources: []string{"ingresses"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
pvcManagement = rule{
|
||||
Name: "pvcManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"persistentvolumeclaims"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
deploymentManagement = rule{
|
||||
Name: "deploymentManagement",
|
||||
Actions: []action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
Resources: []string{
|
||||
"deployments",
|
||||
"deployments/rollback",
|
||||
"deployments/scale",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
Resources: []string{"deployments"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete", "deletecollection"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
Resources: []string{"deployments"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
Resources: []string{"deployments", "deployments/rollback"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "scale",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create", "update", "patch", "delete"},
|
||||
APIGroups: []string{"apps", "extensions"},
|
||||
Resources: []string{"deployments/scale"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
projectManagement = rule{
|
||||
Name: "projectManagement",
|
||||
Actions: []action{
|
||||
{Name: "memberManagement",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list", "create", "delete"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"rolebindings"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "memberRoleManagement",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list", "create", "delete"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"roles"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"extend.kubesphere.io"},
|
||||
Resources: []string{"namespace"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
226
pkg/apis/v1alpha/iam/tools.go
Normal file
226
pkg/apis/v1alpha/iam/tools.go
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
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 iam
|
||||
|
||||
import (
|
||||
"k8s.io/api/rbac/v1"
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
)
|
||||
|
||||
func getUserRules(username string) (map[string][]rule, error) {
|
||||
|
||||
items := make(map[string][]rule, 0)
|
||||
roles, err := models.GetRoles(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
namespaces := make([]string, 0)
|
||||
|
||||
for i := 0; i < len(roles); i++ {
|
||||
if !slice.ContainsString(namespaces, roles[i].Namespace, nil) {
|
||||
namespaces = append(namespaces, roles[i].Namespace)
|
||||
}
|
||||
}
|
||||
|
||||
for _, namespace := range namespaces {
|
||||
rules := getMergeRules(namespace, roles)
|
||||
if len(rules) > 0 {
|
||||
items[namespace] = rules
|
||||
}
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func getMergeRules(namespace string, roles []v1.Role) []rule {
|
||||
rules := make([]rule, 0)
|
||||
|
||||
for i := 0; i < (len(roleRuleGroup)); i++ {
|
||||
rule := rule{Name: roleRuleGroup[i].Name}
|
||||
rule.Actions = make([]action, 0)
|
||||
for j := 0; j < (len(roleRuleGroup[i].Actions)); j++ {
|
||||
permit := false
|
||||
for _, role := range roles {
|
||||
if role.Namespace == namespace && actionValidate(role.Rules, roleRuleGroup[i].Actions[j]) {
|
||||
permit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if permit {
|
||||
rule.Actions = append(rule.Actions, roleRuleGroup[i].Actions[j])
|
||||
}
|
||||
}
|
||||
|
||||
if len(rule.Actions) > 0 {
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
func getUserClusterRules(username string) ([]rule, error) {
|
||||
|
||||
rules := make([]rule, 0)
|
||||
|
||||
roles, err := models.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := 0; i < (len(clusterRoleRuleGroup)); i++ {
|
||||
rule := rule{Name: clusterRoleRuleGroup[i].Name}
|
||||
rule.Actions = make([]action, 0)
|
||||
for j := 0; j < (len(clusterRoleRuleGroup[i].Actions)); j++ {
|
||||
actionPermit := false
|
||||
for _, role := range roles {
|
||||
if actionValidate(role.Rules, clusterRoleRuleGroup[i].Actions[j]) {
|
||||
actionPermit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if actionPermit {
|
||||
rule.Actions = append(rule.Actions, clusterRoleRuleGroup[i].Actions[j])
|
||||
}
|
||||
}
|
||||
|
||||
if len(rule.Actions) > 0 {
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func getClusterRoleRules(name string) ([]rule, error) {
|
||||
|
||||
clusterRole, err := models.GetClusterRole(name)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rules := make([]rule, 0)
|
||||
|
||||
for i := 0; i < len(clusterRoleRuleGroup); i ++ {
|
||||
rule := rule{Name: clusterRoleRuleGroup[i].Name}
|
||||
rule.Actions = make([]action, 0)
|
||||
for j := 0; j < (len(clusterRoleRuleGroup[i].Actions)); j++ {
|
||||
if actionValidate(clusterRole.Rules, clusterRoleRuleGroup[i].Actions[j]) {
|
||||
rule.Actions = append(rule.Actions, clusterRoleRuleGroup[i].Actions[j])
|
||||
}
|
||||
}
|
||||
if len(rule.Actions) > 0 {
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func getRoleRules(namespace string, name string) ([]rule, error) {
|
||||
role, err := models.GetRole(namespace, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules := make([]rule, 0)
|
||||
for i := 0; i < len(roleRuleGroup); i ++ {
|
||||
rule := rule{Name: roleRuleGroup[i].Name}
|
||||
rule.Actions = make([]action, 0)
|
||||
for j := 0; j < len(roleRuleGroup[i].Actions); j++ {
|
||||
if actionValidate(role.Rules, roleRuleGroup[i].Actions[j]) {
|
||||
rule.Actions = append(rule.Actions, roleRuleGroup[i].Actions[j])
|
||||
}
|
||||
}
|
||||
if len(rule.Actions) > 0 {
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
}
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
func actionValidate(rules []v1.PolicyRule, action action) bool {
|
||||
for _, rule := range action.Rules {
|
||||
if !ruleValidate(rules, rule) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ruleValidate(rules []v1.PolicyRule, rule v1.PolicyRule) bool {
|
||||
|
||||
for _, apiGroup := range rule.APIGroups {
|
||||
if len(rule.NonResourceURLs) == 0 {
|
||||
for _, resource := range rule.Resources {
|
||||
|
||||
//if len(rule.ResourceNames) == 0 {
|
||||
|
||||
for _, verb := range rule.Verbs {
|
||||
if !verbValidate(rules, apiGroup, "", resource, "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
//} else {
|
||||
// for _, resourceName := range rule.ResourceNames {
|
||||
// for _, verb := range rule.Verbs {
|
||||
// if !verbValidate(rules, apiGroup, "", resource, resourceName, verb) {
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
for _, nonResourceURL := range rule.NonResourceURLs {
|
||||
for _, verb := range rule.Verbs {
|
||||
if !verbValidate(rules, apiGroup, nonResourceURL, "", "", verb) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func verbValidate(rules []v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, resourceName string, verb string) bool {
|
||||
for _, rule := range rules {
|
||||
if slice.ContainsString(rule.APIGroups, apiGroup, nil) || slice.ContainsString(rule.APIGroups, v1.APIGroupAll, nil) {
|
||||
if slice.ContainsString(rule.Verbs, verb, nil) || slice.ContainsString(rule.Verbs, v1.VerbAll, nil) {
|
||||
if nonResourceURL == "" {
|
||||
if slice.ContainsString(rule.Resources, resource, nil) || slice.ContainsString(rule.Resources, v1.ResourceAll, nil) {
|
||||
if resourceName == "" {
|
||||
return true
|
||||
} else if slice.ContainsString(rule.ResourceNames, resourceName, nil) || slice.ContainsString(rule.Resources, v1.ResourceAll, nil) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
} else if slice.ContainsString(rule.NonResourceURLs, nonResourceURL, nil) || slice.ContainsString(rule.NonResourceURLs, v1.NonResourceAll, nil) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/registries"
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/storage"
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/volumes"
|
||||
"kubesphere.io/kubesphere/pkg/apis/v1alpha/iam"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -41,6 +42,7 @@ func init() {
|
||||
nodes.Register(ws, "/nodes")
|
||||
pods.Register(ws)
|
||||
containers.Register(ws)
|
||||
iam.Register(ws)
|
||||
// add webservice to default container
|
||||
restful.Add(ws)
|
||||
|
||||
|
||||
@@ -4,16 +4,42 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/filter/route"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Register(ws *restful.WebService, subPath string) {
|
||||
ws.Route(ws.GET(subPath+"/storageclasses/{storageclass}/persistentvolumeclaims").
|
||||
To(models.GetPvcListBySc).Filter(route.RouteLogging)).
|
||||
To(GetPvcListBySc).Filter(route.RouteLogging)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
|
||||
ws.Route(ws.GET(subPath+"/storageclasses/{storageclass}/metrics").
|
||||
To(models.GetScMetrics).Filter(route.RouteLogging)).
|
||||
To(GetScMetrics).Filter(route.RouteLogging)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
}
|
||||
|
||||
// List all PersistentVolumeClaims of a specific StorageClass
|
||||
// Extended API URL: "GET /api/v1alpha/storage/storageclasses/{name}/persistentvolumeclaims"
|
||||
func GetPvcListBySc(request *restful.Request, response *restful.Response) {
|
||||
scName := request.PathParameter("storageclass")
|
||||
claims, err := models.GetPvcListBySc(scName)
|
||||
if err != nil {
|
||||
response.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
result := models.PvcListBySc{scName, claims}
|
||||
|
||||
response.WriteAsJson(result)
|
||||
}
|
||||
|
||||
// Get metrics of a specific StorageClass
|
||||
// Extended API URL: "GET /api/v1alpha/storage/storageclasses/{name}/metrics"
|
||||
func GetScMetrics(request *restful.Request, response *restful.Response) {
|
||||
scName := request.PathParameter("storageclass")
|
||||
metrics, err := models.GetScMetrics(scName)
|
||||
if err != nil {
|
||||
response.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
result := models.ScMetrics{Name: scName, Metrics: metrics}
|
||||
response.WriteAsJson(result)
|
||||
}
|
||||
|
||||
@@ -4,11 +4,25 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"kubesphere.io/kubesphere/pkg/filter/route"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Register(ws *restful.WebService, subPath string) {
|
||||
ws.Route(ws.GET(subPath+"/namespaces/{namespace}/persistentvolumeclaims/{pvc}/pods").
|
||||
To(models.GetPodListByPvc).Filter(route.RouteLogging)).
|
||||
To(GetPodListByPvc).Filter(route.RouteLogging)).
|
||||
Consumes(restful.MIME_JSON, restful.MIME_XML).
|
||||
Produces(restful.MIME_JSON)
|
||||
}
|
||||
|
||||
// List all pods of a specific PVC
|
||||
// Extended API URL: "GET /api/v1alpha/volumes/namespaces/{namespace}/persistentvolumeclaims/{name}/pods"
|
||||
func GetPodListByPvc(request *restful.Request, response *restful.Response) {
|
||||
pvcName := request.PathParameter("pvc")
|
||||
nsName := request.PathParameter("namespace")
|
||||
pods, err := models.GetPodListByPvc(pvcName, nsName)
|
||||
if err != nil {
|
||||
response.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
result := models.PodListByPvc{Name: pvcName, Namespace: nsName, Pods: pods}
|
||||
response.WriteAsJson(result)
|
||||
}
|
||||
|
||||
@@ -20,19 +20,21 @@ import (
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/golang/glog"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Route Filter (defines FilterFunction)
|
||||
func RouteLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
|
||||
|
||||
start := time.Now()
|
||||
chain.ProcessFilter(req, resp)
|
||||
glog.Infof("%s - \"%s %s %s\" %d %d",
|
||||
glog.Infof("%s - \"%s %s %s\" %d %dms",
|
||||
strings.Split(req.Request.RemoteAddr, ":")[0],
|
||||
req.Request.Method,
|
||||
req.Request.URL.RequestURI(),
|
||||
req.Request.Proto,
|
||||
resp.StatusCode(),
|
||||
resp.ContentLength(),
|
||||
time.Now().Sub(start)/1000000,
|
||||
)
|
||||
|
||||
}
|
||||
139
pkg/models/roles.go
Normal file
139
pkg/models/roles.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"k8s.io/api/rbac/v1"
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
const ClusterRoleKind = "ClusterRole"
|
||||
|
||||
func GetRole(namespace string, name string) (*v1.Role, error) {
|
||||
k8s := client.NewK8sClient()
|
||||
role, err := k8s.RbacV1().Roles(namespace).Get(name, meta_v1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
|
||||
func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) {
|
||||
k8s := client.NewK8sClient()
|
||||
roleBindingList, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]v1.ClusterRoleBinding, 0)
|
||||
|
||||
for _, roleBinding := range roleBindingList.Items {
|
||||
if roleBinding.RoleRef.Name == name {
|
||||
items = append(items, roleBinding)
|
||||
}
|
||||
}
|
||||
|
||||
return roleBindingList.Items, nil
|
||||
}
|
||||
|
||||
func GetRoleBindings(namespace string, name string) ([]v1.RoleBinding, error) {
|
||||
k8s := client.NewK8sClient()
|
||||
|
||||
roleBindingList, err := k8s.RbacV1().RoleBindings(namespace).List(meta_v1.ListOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
items := make([]v1.RoleBinding, 0)
|
||||
|
||||
for _, roleBinding := range roleBindingList.Items {
|
||||
if roleBinding.RoleRef.Name == name {
|
||||
items = append(items, roleBinding)
|
||||
}
|
||||
}
|
||||
|
||||
return roleBindingList.Items, nil
|
||||
}
|
||||
|
||||
func GetClusterRole(name string) (*v1.ClusterRole, error) {
|
||||
k8s := client.NewK8sClient()
|
||||
role, err := k8s.RbacV1().ClusterRoles().Get(name, meta_v1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
|
||||
func GetRoles(username string) ([]v1.Role, error) {
|
||||
k8s := client.NewK8sClient()
|
||||
|
||||
roleBindings, err := k8s.RbacV1().RoleBindings("").List(meta_v1.ListOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
roles := make([]v1.Role, 0)
|
||||
|
||||
for _, roleBinding := range roleBindings.Items {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
|
||||
clusterRole, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var role = v1.Role(*clusterRole)
|
||||
role.Namespace = roleBinding.Namespace
|
||||
|
||||
roles = append(roles, role)
|
||||
|
||||
} else {
|
||||
rule, err := k8s.RbacV1().Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles = append(roles, *rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
||||
k8s := client.NewK8sClient()
|
||||
|
||||
clusterRoleBindings, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles := make([]v1.ClusterRole, 0)
|
||||
|
||||
for _, roleBinding := range clusterRoleBindings.Items {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
|
||||
rule, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roles = append(roles, *rule)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return roles, nil
|
||||
}
|
||||
@@ -1,61 +1,28 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
v12 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type pvcListBySc struct {
|
||||
type PvcListBySc struct {
|
||||
Name string `json:"name"`
|
||||
Claims []v12.PersistentVolumeClaim `json:"persistentvolumeclaims"`
|
||||
Claims []v12.PersistentVolumeClaim `json:"items"`
|
||||
}
|
||||
|
||||
type scMetrics struct {
|
||||
type ScMetrics struct {
|
||||
Name string `json:"name"`
|
||||
Metrics storageMetrics `json:"metrics"`
|
||||
Metrics StorageMetrics `json:"metrics"`
|
||||
}
|
||||
|
||||
type storageMetrics struct {
|
||||
type StorageMetrics struct {
|
||||
Capacity string `json:"capacity,omitempty"`
|
||||
Usage string `json:"usage,omitempty"`
|
||||
}
|
||||
|
||||
// List all PersistentVolumeClaims of a specific StorageClass
|
||||
// Extended API URL: "GET /api/v1alpha/storage/storageclasses/{name}/persistentvolumeclaims"
|
||||
func GetPvcListBySc(request *restful.Request, response *restful.Response) {
|
||||
scName := request.PathParameter("storageclass")
|
||||
claims, err := getPvcListBySc(scName)
|
||||
if err != nil {
|
||||
response.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
result := constants.ResultMessage{
|
||||
|
||||
Data: pvcListBySc{scName, claims}}
|
||||
|
||||
response.WriteAsJson(result)
|
||||
}
|
||||
|
||||
// Get metrics of a specific StorageClass
|
||||
// Extended API URL: "GET /api/v1alpha/storage/storageclasses/{name}/metrics"
|
||||
func GetScMetrics(request *restful.Request, response *restful.Response) {
|
||||
scName := request.PathParameter("storageclass")
|
||||
metrics, err := getScMetrics(scName)
|
||||
if err != nil {
|
||||
response.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
result := constants.ResultMessage{
|
||||
|
||||
Data: scMetrics{Name: scName, Metrics: metrics},
|
||||
}
|
||||
response.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func getPvcListBySc(storageclass string) (res []v12.PersistentVolumeClaim, err error) {
|
||||
func GetPvcListBySc(storageclass string) (res []v12.PersistentVolumeClaim, err error) {
|
||||
|
||||
cli := client.NewK8sClient()
|
||||
claimList, err := cli.CoreV1().PersistentVolumeClaims("").List(v1.ListOptions{})
|
||||
@@ -72,11 +39,11 @@ func getPvcListBySc(storageclass string) (res []v12.PersistentVolumeClaim, err e
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func getScMetrics(storageclass string) (res storageMetrics, err error) {
|
||||
func GetScMetrics(storageclass string) (res StorageMetrics, err error) {
|
||||
cli := client.NewK8sClient()
|
||||
pvList, err := cli.CoreV1().PersistentVolumes().List(v1.ListOptions{})
|
||||
if err != nil {
|
||||
return storageMetrics{}, err
|
||||
return StorageMetrics{}, err
|
||||
}
|
||||
|
||||
var total resource.Quantity
|
||||
@@ -86,5 +53,5 @@ func getScMetrics(storageclass string) (res storageMetrics, err error) {
|
||||
}
|
||||
total.Add(volume.Spec.Capacity[v12.ResourceStorage])
|
||||
}
|
||||
return storageMetrics{Usage: total.String()}, nil
|
||||
return StorageMetrics{Usage: total.String()}, nil
|
||||
}
|
||||
|
||||
@@ -1,39 +1,18 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful"
|
||||
v12 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type podListByPvc struct {
|
||||
type PodListByPvc struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Pods []v12.Pod `json:"pods"`
|
||||
}
|
||||
|
||||
// List all pods of a specific PVC
|
||||
// Extended API URL: "GET /api/v1alpha/volumes/namespaces/{namespace}/persistentvolumeclaims/{name}/pods"
|
||||
func GetPodListByPvc(request *restful.Request, response *restful.Response) {
|
||||
|
||||
pvcName := request.PathParameter("pvc")
|
||||
nsName := request.PathParameter("namespace")
|
||||
pods, err := getPodListByPvc(pvcName, nsName)
|
||||
if err != nil {
|
||||
response.WriteError(http.StatusInternalServerError, err)
|
||||
}
|
||||
result := constants.ResultMessage{
|
||||
|
||||
Data: podListByPvc{
|
||||
Name: pvcName, Namespace: nsName, Pods: pods}}
|
||||
|
||||
response.WriteAsJson(result)
|
||||
}
|
||||
|
||||
func getPodListByPvc(pvc string, ns string) (res []v12.Pod, err error) {
|
||||
func GetPodListByPvc(pvc string, ns string) (res []v12.Pod, err error) {
|
||||
cli := client.NewK8sClient()
|
||||
podList, err := cli.CoreV1().Pods(ns).List(v1.ListOptions{})
|
||||
if err != nil {
|
||||
@@ -41,14 +20,14 @@ func getPodListByPvc(pvc string, ns string) (res []v12.Pod, err error) {
|
||||
}
|
||||
|
||||
for _, pod := range podList.Items {
|
||||
if isPvcInPod(pod, pvc) == true {
|
||||
if IsPvcInPod(pod, pvc) == true {
|
||||
res = append(res, pod)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func isPvcInPod(pod v12.Pod, pvcname string) bool {
|
||||
func IsPvcInPod(pod v12.Pod, pvcname string) bool {
|
||||
for _, v := range pod.Spec.Volumes {
|
||||
if v.VolumeSource.PersistentVolumeClaim != nil &&
|
||||
v.VolumeSource.PersistentVolumeClaim.ClaimName == pvcname {
|
||||
|
||||
Reference in New Issue
Block a user