Merge remote-tracking branch 'origin/master'

This commit is contained in:
yanmingfan
2018-06-01 11:10:37 +08:00
12 changed files with 1095 additions and 74 deletions

9
.gitignore vendored
View File

@@ -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

View File

@@ -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() {

View 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)
}

View 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"},
},
},
},
},
}
)

View 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
}

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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
View 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
}

View File

@@ -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
}

View File

@@ -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 {