From 2ab1ab7b98f155a768e3e0471ca30d77702071db Mon Sep 17 00:00:00 2001 From: runzexia Date: Wed, 24 Apr 2019 21:51:43 +0800 Subject: [PATCH] devops project api & devops members api Signed-off-by: runzexia --- pkg/apis/devops/install/install.go | 25 +- pkg/apis/devops/v1alpha2/register.go | 72 ++++- pkg/apiserver/devops/member.go | 196 ++++++++++++ pkg/apiserver/devops/project.go | 69 +++++ pkg/apiserver/tenant/tenant.go | 22 +- pkg/errors/errors.go | 10 + pkg/models/devops/common.go | 254 ++++++++++++++++ pkg/models/devops/project_handler.go | 64 ++++ pkg/models/devops/project_member_handler.go | 318 ++++++++++++++++++++ pkg/models/tenant/devops.go | 316 +++---------------- 10 files changed, 1039 insertions(+), 307 deletions(-) create mode 100644 pkg/apiserver/devops/member.go create mode 100644 pkg/apiserver/devops/project.go create mode 100644 pkg/models/devops/project_handler.go create mode 100644 pkg/models/devops/project_member_handler.go diff --git a/pkg/apis/devops/install/install.go b/pkg/apis/devops/install/install.go index 035d6a367..306edb599 100644 --- a/pkg/apis/devops/install/install.go +++ b/pkg/apis/devops/install/install.go @@ -1,20 +1,21 @@ /* - Copyright 2019 The KubeSphere Authors. + 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 + 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 + 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. + 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 install import ( @@ -28,6 +29,6 @@ func init() { Install(runtime.Container) } -func Install(c *restful.Container) { - urlruntime.Must(devopsv1alpha2.AddToContainer(c)) +func Install(container *restful.Container) { + urlruntime.Must(devopsv1alpha2.AddToContainer(container)) } diff --git a/pkg/apis/devops/v1alpha2/register.go b/pkg/apis/devops/v1alpha2/register.go index 58d36287b..1d92fc13e 100644 --- a/pkg/apis/devops/v1alpha2/register.go +++ b/pkg/apis/devops/v1alpha2/register.go @@ -15,14 +15,16 @@ limitations under the License. */ + package v1alpha2 import ( "github.com/emicklei/go-restful" "github.com/emicklei/go-restful-openapi" "k8s.io/apimachinery/pkg/runtime/schema" - "kubesphere.io/kubesphere/pkg/apiserver/devops" + devopsapi "kubesphere.io/kubesphere/pkg/apiserver/devops" "kubesphere.io/kubesphere/pkg/apiserver/runtime" + "kubesphere.io/kubesphere/pkg/models/devops" ) const GroupName = "devops.kubesphere.io" @@ -35,13 +37,63 @@ var ( ) func addWebService(c *restful.Container) error { + webservice := runtime.NewWebService(GroupVersion) - tags := []string{"devops"} + tags := []string{"DevOps"} + + webservice.Route(webservice.GET("/devops/{devops}"). + To(devopsapi.GetDevOpsProjectHandler). + Doc("get devops project"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Param(webservice.PathParameter("devops", "projectId")). + Writes(&devops.DevOpsProject{})) + + webservice.Route(webservice.PATCH("/devops/{devops}"). + To(devopsapi.UpdateProjectHandler). + Doc("get devops project"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Param(webservice.PathParameter("devops", "projectId")). + Writes(&devops.DevOpsProject{})) + + webservice.Route(webservice.GET("/devops/{devops}/defaultroles"). + To(devopsapi.GetDevOpsProjectDefaultRoles). + Doc("get devops project defaultroles"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Writes(&devops.DefaultRoles)) + + webservice.Route(webservice.GET("/devops/{devops}/members"). + To(devopsapi.GetDevOpsProjectMembersHandler). + Doc("get devops project members"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Writes(&[]*devops.DevOpsProjectMembership{})) + + webservice.Route(webservice.GET("/devops/{devops}/members/{members}"). + To(devopsapi.GetDevOpsProjectMemberHandler). + Doc("get devops project member"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Writes(&devops.DevOpsProjectMembership{})) + + webservice.Route(webservice.POST("/devops/{devops}/members"). + To(devopsapi.AddDevOpsProjectMemberHandler). + Doc("add devops project members"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Writes(&devops.DevOpsProjectMembership{})) + + webservice.Route(webservice.PATCH("/devops/{devops}/members/{members}"). + To(devopsapi.UpdateDevOpsProjectMemberHandler). + Doc("update devops project members"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Writes(&devops.DevOpsProjectMembership{})) + webservice.Route(webservice.DELETE("/devops/{devops}/members/{members}"). + To(devopsapi.DeleteDevOpsProjectMemberHandler). + Doc("delete devops project members"). + Metadata(restfulspec.KeyOpenAPITags, tags). + Writes(&devops.DevOpsProjectMembership{})) // match Jenkisn api "/blue/rest/organizations/jenkins/pipelines/{projectName}/{pipelineName}" webservice.Route(webservice.GET("/devops/{projectName}/pipelines/{pipelineName}"). - To(devops.GetPipeline). + To(devopsapi.GetPipeline). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get DevOps Pipelines."). Param(webservice.PathParameter("pipelineName", "pipeline name")). @@ -49,7 +101,7 @@ func addWebService(c *restful.Container) error { // match Jenkisn api: "jenkins_api/blue/rest/search" webservice.Route(webservice.GET("/devops/search"). - To(devops.SearchPipelines). + To(devopsapi.SearchPipelines). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Search DevOps resource."). Param(webservice.QueryParameter("q", "query pipelines"). @@ -67,7 +119,7 @@ func addWebService(c *restful.Container) error { // match Jenkisn api "/blue/rest/organizations/jenkins/pipelines/{projectName}/{pipelineName}/runs/" webservice.Route(webservice.GET("/devops/{projectName}/pipelines/{pipelineName}/runs"). - To(devops.SearchPipelineRuns). + To(devopsapi.SearchPipelineRuns). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Search DevOps Pipelines runs."). Param(webservice.PathParameter("pipelineName", "pipeline name")). @@ -81,7 +133,7 @@ func addWebService(c *restful.Container) error { // match Jenkins api "/blue/rest/organizations/jenkins/pipelines/{projectName}/{pipelineName}/branches/{branchName}/runs/{runId}/" webservice.Route(webservice.GET("/devops/{projectName}/pipelines/{pipelineName}/branches/{branchName}/runs/{runId}"). - To(devops.GetPipelineRun). + To(devopsapi.GetPipelineRun). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get DevOps Pipelines run."). Param(webservice.PathParameter("pipelineName", "pipeline name")). @@ -91,7 +143,7 @@ func addWebService(c *restful.Container) error { // match Jenkins api "/blue/rest/organizations/jenkins/pipelines/{projectName}/{pipelineName}/branches/{branchName}/runs/{runId}/nodes" webservice.Route(webservice.GET("/devops/{projectName}/pipelines/{pipelineName}/branches/{branchName}/runs/{runId}/nodes"). - To(devops.GetPipelineRunNodes). + To(devopsapi.GetPipelineRunNodes). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get node on DevOps Pipelines run."). Param(webservice.PathParameter("projectName", "devops project name")). @@ -105,7 +157,7 @@ func addWebService(c *restful.Container) error { // match "/blue/rest/organizations/jenkins/pipelines/{projectName}/{pipelineName}/branches/{branchName}/runs/{runId}/nodes/{nodeId}/steps/{stepId}/log/?start=0" webservice.Route(webservice.GET("/devops/{projectName}/pipelines/{pipelineName}/branches/{branchName}/runs/{runId}/nodes/{nodeId}/steps/{stepId}/log"). - To(devops.GetStepLog). + To(devopsapi.GetStepLog). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get Pipelines step log."). Param(webservice.PathParameter("projectName", "devops project name")). @@ -121,14 +173,14 @@ func addWebService(c *restful.Container) error { // match "/blue/rest/organizations/jenkins/scm/github/validate/" webservice.Route(webservice.PUT("/devops/scm/{scmId}/validate"). - To(devops.Validate). + To(devopsapi.Validate). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Validate Github personal access token."). Param(webservice.PathParameter("scmId", "SCM id"))) // match "/blue/rest/organizations/jenkins/scm/{scmId}/organizations/?credentialId=github" webservice.Route(webservice.GET("/devops/scm/{scmId}/organizations"). - To(devops.GetOrgSCM). + To(devopsapi.GetOrgSCM). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("List organizations of SCM"). Param(webservice.PathParameter("scmId", "SCM id")). diff --git a/pkg/apiserver/devops/member.go b/pkg/apiserver/devops/member.go new file mode 100644 index 000000000..382bafd3f --- /dev/null +++ b/pkg/apiserver/devops/member.go @@ -0,0 +1,196 @@ +package devops + +import ( + "fmt" + "github.com/asaskevich/govalidator" + "github.com/emicklei/go-restful" + "github.com/golang/glog" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/errors" + "kubesphere.io/kubesphere/pkg/models/devops" + "kubesphere.io/kubesphere/pkg/params" + "kubesphere.io/kubesphere/pkg/utils/reflectutils" + "net/http" +) + +/* +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. +*/ + +func GetDevOpsProjectMembersHandler(request *restful.Request, resp *restful.Response) { + + projectId := request.PathParameter("devops") + username := request.HeaderParameter(constants.UserNameHeader) + + err := devops.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp) + return + } + orderBy := request.QueryParameter(params.OrderByParam) + reverse := params.ParseReverse(request) + limit, offset := params.ParsePaging(request.QueryParameter(params.PagingParam)) + conditions, err := params.ParseConditions(request.QueryParameter(params.ConditionsParam)) + + project, err := devops.GetProjectMembers(projectId, conditions, orderBy, reverse, limit, offset) + + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + + resp.WriteAsJson(project) + return +} + +func GetDevOpsProjectMemberHandler(request *restful.Request, resp *restful.Response) { + + projectId := request.PathParameter("devops") + username := request.HeaderParameter(constants.UserNameHeader) + member := request.PathParameter("members") + + err := devops.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp) + return + } + project, err := devops.GetProjectMember(projectId, member) + + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + + resp.WriteAsJson(project) + return +} + +func AddDevOpsProjectMemberHandler(request *restful.Request, resp *restful.Response) { + + projectId := request.PathParameter("devops") + username := request.HeaderParameter(constants.UserNameHeader) + member := &devops.DevOpsProjectMembership{} + err := request.ReadEntity(&member) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + if govalidator.IsNull(member.Username) { + err := fmt.Errorf("error need username") + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + if !reflectutils.In(member.Role, devops.AllRoleSlice) { + err := fmt.Errorf("err role [%s] not in [%s]", member.Role, + devops.AllRoleSlice) + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + + err = devops.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp) + return + } + project, err := devops.AddProjectMember(projectId, username, member) + + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + + resp.WriteAsJson(project) + return +} + +func UpdateDevOpsProjectMemberHandler(request *restful.Request, resp *restful.Response) { + + projectId := request.PathParameter("devops") + username := request.HeaderParameter(constants.UserNameHeader) + member := &devops.DevOpsProjectMembership{} + err := request.ReadEntity(&member) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + member.Username = request.PathParameter("members") + if govalidator.IsNull(member.Username) { + err := fmt.Errorf("error need username") + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + if username == member.Username { + err := fmt.Errorf("you can not change your role") + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + if !reflectutils.In(member.Role, devops.AllRoleSlice) { + err := fmt.Errorf("err role [%s] not in [%s]", member.Role, + devops.AllRoleSlice) + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + + err = devops.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp) + return + } + project, err := devops.UpdateProjectMember(projectId, username, member) + + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + + resp.WriteAsJson(project) + return +} + +func DeleteDevOpsProjectMemberHandler(request *restful.Request, resp *restful.Response) { + + projectId := request.PathParameter("devops") + username := request.HeaderParameter(constants.UserNameHeader) + member := request.PathParameter("members") + + err := devops.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp) + return + } + username, err = devops.DeleteProjectMember(projectId, member) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + resp.WriteAsJson(struct { + Username string `json:"username"` + }{Username: username}) + return +} diff --git a/pkg/apiserver/devops/project.go b/pkg/apiserver/devops/project.go new file mode 100644 index 000000000..630fd8eb1 --- /dev/null +++ b/pkg/apiserver/devops/project.go @@ -0,0 +1,69 @@ +package devops + +import ( + "github.com/emicklei/go-restful" + "github.com/golang/glog" + + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/errors" + "kubesphere.io/kubesphere/pkg/models/devops" + "net/http" +) + +func GetDevOpsProjectHandler(request *restful.Request, resp *restful.Response) { + + projectId := request.PathParameter("devops") + username := request.HeaderParameter(constants.UserNameHeader) + + err := devops.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp) + return + } + project, err := devops.GetProject(projectId) + + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + + resp.WriteAsJson(project) + return +} + +func UpdateProjectHandler(request *restful.Request, resp *restful.Response) { + + projectId := request.PathParameter("devops") + username := request.HeaderParameter(constants.UserNameHeader) + var project *devops.DevOpsProject + err := request.ReadEntity(&project) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) + return + } + project.ProjectId = projectId + err = devops.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusForbidden, err.Error()), resp) + return + } + project, err = devops.UpdateProject(project) + + if err != nil { + glog.Errorf("%+v", err) + errors.ParseSvcErr(err, resp) + return + } + + resp.WriteAsJson(project) + return +} + +func GetDevOpsProjectDefaultRoles(request *restful.Request, resp *restful.Response) { + resp.WriteAsJson(devops.DefaultRoles) + return +} diff --git a/pkg/apiserver/tenant/tenant.go b/pkg/apiserver/tenant/tenant.go index 41ecd7fb2..a3144f921 100644 --- a/pkg/apiserver/tenant/tenant.go +++ b/pkg/apiserver/tenant/tenant.go @@ -217,7 +217,7 @@ func ListDevopsProjects(req *restful.Request, resp *restful.Response) { if err != nil { glog.Errorf("%+v", err) - resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err)) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) return } @@ -225,7 +225,7 @@ func ListDevopsProjects(req *restful.Request, resp *restful.Response) { if err != nil { glog.Errorf("%+v", err) - resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err)) + errors.ParseSvcErr(err, resp) return } @@ -233,7 +233,7 @@ func ListDevopsProjects(req *restful.Request, resp *restful.Response) { } func DeleteDevopsProject(req *restful.Request, resp *restful.Response) { - devops := req.PathParameter("id") + projectId := req.PathParameter("id") workspaceName := req.PathParameter("workspace") username := req.HeaderParameter(constants.UserNameHeader) @@ -241,15 +241,15 @@ func DeleteDevopsProject(req *restful.Request, resp *restful.Response) { if err != nil { glog.Errorf("%+v", err) - resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err)) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) return } - err, code := tenant.DeleteDevOpsProject(devops, username) + err = tenant.DeleteDevOpsProject(projectId, username) if err != nil { glog.Errorf("%+v", err) - resp.WriteHeaderAndEntity(code, errors.Wrap(err)) + errors.ParseSvcErr(err, resp) return } @@ -267,16 +267,16 @@ func CreateDevopsProject(req *restful.Request, resp *restful.Response) { if err != nil { glog.Infof("%+v", err) - resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err)) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), resp) return } glog.Infoln("create workspace", username, workspaceName, devops) - project, err, code := tenant.CreateDevopsProject(username, workspaceName, &devops) + project, err := tenant.CreateDevopsProject(username, workspaceName, &devops) if err != nil { glog.Errorf("%+v", err) - resp.WriteHeaderAndEntity(code, errors.Wrap(err)) + errors.ParseSvcErr(err, resp) return } @@ -302,11 +302,11 @@ func ListDevopsRules(req *restful.Request, resp *restful.Response) { devops := req.PathParameter("devops") username := req.HeaderParameter(constants.UserNameHeader) - rules, err, code := tenant.GetUserDevopsSimpleRules(username, devops) + rules, err := tenant.GetUserDevopsSimpleRules(username, devops) if err != nil { glog.Errorf("%+v", err) - resp.WriteError(code, err) + errors.ParseSvcErr(err, resp) return } diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 8a3966608..75bab86a9 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -20,6 +20,8 @@ package errors import ( "encoding/json" "errors" + "github.com/emicklei/go-restful" + "net/http" ) type Error struct { @@ -53,3 +55,11 @@ func Parse(data []byte) error { return errors.New(string(data)) } } + +func ParseSvcErr(err error, resp *restful.Response) { + if svcErr, ok := err.(restful.ServiceError); ok { + resp.WriteServiceError(svcErr.Code, svcErr) + } else { + resp.WriteHeaderAndEntity(http.StatusInternalServerError, Wrap(err)) + } +} diff --git a/pkg/models/devops/common.go b/pkg/models/devops/common.go index 44ac74fe5..453531224 100644 --- a/pkg/models/devops/common.go +++ b/pkg/models/devops/common.go @@ -1,7 +1,12 @@ package devops import ( + "fmt" "github.com/fatih/structs" + "kubesphere.io/kubesphere/pkg/db" + "kubesphere.io/kubesphere/pkg/gojenkins" + "kubesphere.io/kubesphere/pkg/simple/client/devops_mysql" + "kubesphere.io/kubesphere/pkg/utils/reflectutils" "kubesphere.io/kubesphere/pkg/utils/stringutils" ) @@ -59,3 +64,252 @@ const ( const ( JenkinsAllUserRoleName = "kubesphere-user" ) + +type Role struct { + Name string `json:"name"` + Description string `json:"description"` +} + +var DefaultRoles = []*Role{ + { + Name: ProjectOwner, + Description: "Owner have access to do all the operations of a DevOps project and own the highest permissions as well.", + }, + { + Name: ProjectMaintainer, + Description: "Maintainer have access to manage pipeline and credential configuration in a DevOps project.", + }, + { + Name: ProjectDeveloper, + Description: "Developer is able to view and trigger the pipeline.", + }, + { + Name: ProjectReporter, + Description: "Reporter is only allowed to view the status of the pipeline.", + }, +} + +var AllRoleSlice = []string{ProjectDeveloper, ProjectReporter, ProjectMaintainer, ProjectOwner} + +var JenkinsOwnerProjectPermissionIds = &gojenkins.ProjectPermissionIds{ + CredentialCreate: true, + CredentialDelete: true, + CredentialManageDomains: true, + CredentialUpdate: true, + CredentialView: true, + ItemBuild: true, + ItemCancel: true, + ItemConfigure: true, + ItemCreate: true, + ItemDelete: true, + ItemDiscover: true, + ItemMove: true, + ItemRead: true, + ItemWorkspace: true, + RunDelete: true, + RunReplay: true, + RunUpdate: true, + SCMTag: true, +} + +var JenkinsProjectPermissionMap = map[string]gojenkins.ProjectPermissionIds{ + ProjectOwner: gojenkins.ProjectPermissionIds{ + CredentialCreate: true, + CredentialDelete: true, + CredentialManageDomains: true, + CredentialUpdate: true, + CredentialView: true, + ItemBuild: true, + ItemCancel: true, + ItemConfigure: true, + ItemCreate: true, + ItemDelete: true, + ItemDiscover: true, + ItemMove: true, + ItemRead: true, + ItemWorkspace: true, + RunDelete: true, + RunReplay: true, + RunUpdate: true, + SCMTag: true, + }, + ProjectMaintainer: gojenkins.ProjectPermissionIds{ + CredentialCreate: true, + CredentialDelete: true, + CredentialManageDomains: true, + CredentialUpdate: true, + CredentialView: true, + ItemBuild: true, + ItemCancel: true, + ItemConfigure: false, + ItemCreate: true, + ItemDelete: false, + ItemDiscover: true, + ItemMove: false, + ItemRead: true, + ItemWorkspace: true, + RunDelete: true, + RunReplay: true, + RunUpdate: true, + SCMTag: true, + }, + ProjectDeveloper: gojenkins.ProjectPermissionIds{ + CredentialCreate: false, + CredentialDelete: false, + CredentialManageDomains: false, + CredentialUpdate: false, + CredentialView: false, + ItemBuild: true, + ItemCancel: true, + ItemConfigure: false, + ItemCreate: false, + ItemDelete: false, + ItemDiscover: true, + ItemMove: false, + ItemRead: true, + ItemWorkspace: true, + RunDelete: true, + RunReplay: true, + RunUpdate: true, + SCMTag: false, + }, + ProjectReporter: gojenkins.ProjectPermissionIds{ + CredentialCreate: false, + CredentialDelete: false, + CredentialManageDomains: false, + CredentialUpdate: false, + CredentialView: false, + ItemBuild: false, + ItemCancel: false, + ItemConfigure: false, + ItemCreate: false, + ItemDelete: false, + ItemDiscover: true, + ItemMove: false, + ItemRead: true, + ItemWorkspace: false, + RunDelete: false, + RunReplay: false, + RunUpdate: false, + SCMTag: false, + }, +} + +var JenkinsPipelinePermissionMap = map[string]gojenkins.ProjectPermissionIds{ + ProjectOwner: gojenkins.ProjectPermissionIds{ + CredentialCreate: true, + CredentialDelete: true, + CredentialManageDomains: true, + CredentialUpdate: true, + CredentialView: true, + ItemBuild: true, + ItemCancel: true, + ItemConfigure: true, + ItemCreate: true, + ItemDelete: true, + ItemDiscover: true, + ItemMove: true, + ItemRead: true, + ItemWorkspace: true, + RunDelete: true, + RunReplay: true, + RunUpdate: true, + SCMTag: true, + }, + ProjectMaintainer: gojenkins.ProjectPermissionIds{ + CredentialCreate: true, + CredentialDelete: true, + CredentialManageDomains: true, + CredentialUpdate: true, + CredentialView: true, + ItemBuild: true, + ItemCancel: true, + ItemConfigure: true, + ItemCreate: true, + ItemDelete: true, + ItemDiscover: true, + ItemMove: true, + ItemRead: true, + ItemWorkspace: true, + RunDelete: true, + RunReplay: true, + RunUpdate: true, + SCMTag: true, + }, + ProjectDeveloper: gojenkins.ProjectPermissionIds{ + CredentialCreate: false, + CredentialDelete: false, + CredentialManageDomains: false, + CredentialUpdate: false, + CredentialView: false, + ItemBuild: true, + ItemCancel: true, + ItemConfigure: false, + ItemCreate: false, + ItemDelete: false, + ItemDiscover: true, + ItemMove: false, + ItemRead: true, + ItemWorkspace: true, + RunDelete: true, + RunReplay: true, + RunUpdate: true, + SCMTag: false, + }, + ProjectReporter: gojenkins.ProjectPermissionIds{ + CredentialCreate: false, + CredentialDelete: false, + CredentialManageDomains: false, + CredentialUpdate: false, + CredentialView: false, + ItemBuild: false, + ItemCancel: false, + ItemConfigure: false, + ItemCreate: false, + ItemDelete: false, + ItemDiscover: true, + ItemMove: false, + ItemRead: true, + ItemWorkspace: false, + RunDelete: false, + RunReplay: false, + RunUpdate: false, + SCMTag: false, + }, +} + +func GetProjectRoleName(projectId, role string) string { + return fmt.Sprintf("%s-%s-project", projectId, role) +} + +func GetPipelineRoleName(projectId, role string) string { + return fmt.Sprintf("%s-%s-pipeline", projectId, role) +} + +func GetProjectRolePattern(projectId string) string { + return fmt.Sprintf("^%s$", projectId) +} + +func GetPipelineRolePattern(projectId string) string { + return fmt.Sprintf("^%s/.*", projectId) +} + +func CheckProjectUserInRole(username, projectId string, roles []string) error { + if username == KS_ADMIN { + return nil + } + dbconn := devops_mysql.OpenDatabase() + membership := &DevOpsProjectMembership{} + err := dbconn.Select(DevOpsProjectMembershipColumns...). + From(DevOpsProjectMembershipTableName). + Where(db.And( + db.Eq(DevOpsProjectMembershipUsernameColumn, username), + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId))).LoadOne(membership) + if err != nil { + return err + } + if !reflectutils.In(membership.Role, roles) { + return fmt.Errorf("user [%s] in project [%s] role is not in %s", username, projectId, roles) + } + return nil +} diff --git a/pkg/models/devops/project_handler.go b/pkg/models/devops/project_handler.go new file mode 100644 index 000000000..f412c5f9b --- /dev/null +++ b/pkg/models/devops/project_handler.go @@ -0,0 +1,64 @@ +package devops + +import ( + "github.com/asaskevich/govalidator" + "github.com/emicklei/go-restful" + "github.com/gocraft/dbr" + "k8s.io/klog/glog" + "kubesphere.io/kubesphere/pkg/db" + "kubesphere.io/kubesphere/pkg/simple/client/devops_mysql" + "net/http" +) + +func GetProject(projectId string) (*DevOpsProject, error) { + dbconn := devops_mysql.OpenDatabase() + project := &DevOpsProject{} + err := dbconn.Select(DevOpsProjectColumns...). + From(DevOpsProjectTableName). + Where(db.Eq(DevOpsProjectIdColumn, projectId)). + LoadOne(project) + if err != nil && err != dbr.ErrNotFound { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + if err == dbr.ErrNotFound { + glog.Errorf("%+v", err) + + return nil, restful.NewError(http.StatusNotFound, err.Error()) + } + return project, nil +} + +func UpdateProject(project *DevOpsProject) (*DevOpsProject, error) { + dbconn := devops_mysql.OpenDatabase() + query := dbconn.Update(DevOpsProjectTableName) + if !govalidator.IsNull(project.Description) { + query.Set(DevOpsProjectDescriptionColumn, project.Description) + } + if !govalidator.IsNull(project.Extra) { + query.Set(DevOpsProjectExtraColumn, project.Extra) + } + if !govalidator.IsNull(project.Name) { + query.Set(DevOpsProjectNameColumn, project.Extra) + } + if len(query.UpdateStmt.Value) > 0 { + _, err := query. + Where(db.Eq(DevOpsProjectIdColumn, project.ProjectId)).Exec() + + if err != nil { + glog.Errorf("%+v", err) + + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + } + newProject := &DevOpsProject{} + err := dbconn.Select(DevOpsProjectColumns...). + From(DevOpsProjectTableName). + Where(db.Eq(DevOpsProjectIdColumn, project.ProjectId)). + LoadOne(newProject) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + return newProject, nil +} diff --git a/pkg/models/devops/project_member_handler.go b/pkg/models/devops/project_member_handler.go new file mode 100644 index 000000000..f1e769255 --- /dev/null +++ b/pkg/models/devops/project_member_handler.go @@ -0,0 +1,318 @@ +package devops + +import ( + "fmt" + "net/http" + + "github.com/emicklei/go-restful" + "github.com/gocraft/dbr" + "github.com/golang/glog" + "kubesphere.io/devops/pkg/utils/stringutils" + "kubesphere.io/kubesphere/pkg/db" + "kubesphere.io/kubesphere/pkg/gojenkins" + "kubesphere.io/kubesphere/pkg/gojenkins/utils" + "kubesphere.io/kubesphere/pkg/models" + "kubesphere.io/kubesphere/pkg/params" + "kubesphere.io/kubesphere/pkg/simple/client/admin_jenkins" + "kubesphere.io/kubesphere/pkg/simple/client/devops_mysql" +) + +/* +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. +*/ + +func GetProjectMembers(projectId string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) { + dbconn := devops_mysql.OpenDatabase() + memberships := make([]*DevOpsProjectMembership, 0) + var sqconditions []dbr.Builder + sqconditions = append(sqconditions, db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId)) + if keyword := conditions.Match["keyword"]; keyword != "" { + sqconditions = append(sqconditions, db.Like(DevOpsProjectMembershipUsernameColumn, keyword)) + } + query := dbconn.Select(DevOpsProjectMembershipColumns...). + From(DevOpsProjectMembershipTableName) + switch orderBy { + case "name": + if reverse { + query.OrderDesc(DevOpsProjectMembershipUsernameColumn) + } else { + query.OrderAsc(DevOpsProjectMembershipUsernameColumn) + } + default: + if reverse { + query.OrderDesc(DevOpsProjectMembershipRoleColumn) + } else { + query.OrderAsc(DevOpsProjectMembershipRoleColumn) + } + } + query.Limit(uint64(limit)) + query.Offset(uint64(offset)) + if len(sqconditions) > 1 { + query.Where(db.And(sqconditions...)) + } else { + query.Where(sqconditions[0]) + } + _, err := query.Load(&memberships) + if err != nil && err != dbr.ErrNotFound { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + count, err := query.Count() + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + result := make([]interface{}, 0) + for _, v := range memberships { + result = append(result, v) + } + + return &models.PageableResponse{Items: result, TotalCount: int(count)}, nil +} + +func GetProjectMember(projectId, username string) (*DevOpsProjectMembership, error) { + dbconn := devops_mysql.OpenDatabase() + member := &DevOpsProjectMembership{} + err := dbconn.Select(DevOpsProjectMembershipColumns...). + From(DevOpsProjectMembershipTableName). + Where(db.And(db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId), + db.Eq(DevOpsProjectMembershipUsernameColumn, username))). + LoadOne(&member) + if err != nil && err != dbr.ErrNotFound { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + if err == dbr.ErrNotFound { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusNotFound, err.Error()) + } + return member, nil +} + +func AddProjectMember(projectId, operator string, member *DevOpsProjectMembership) (*DevOpsProjectMembership, error) { + dbconn := devops_mysql.OpenDatabase() + jenkinsClinet := admin_jenkins.Client() + + membership := &DevOpsProjectMembership{} + err := dbconn.Select(DevOpsProjectMembershipColumns...). + From(DevOpsProjectMembershipTableName). + Where(db.And( + db.Eq(DevOpsProjectMembershipUsernameColumn, member.Username), + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId))).LoadOne(membership) + if err != nil && err != db.ErrNotFound { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + if err != db.ErrNotFound { + err = fmt.Errorf("user [%s] have been added to project", member.Username) + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusBadRequest, err.Error()) + } + + globalRole, err := jenkinsClinet.GetGlobalRole(JenkinsAllUserRoleName) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + if globalRole == nil { + _, err := jenkinsClinet.AddGlobalRole(JenkinsAllUserRoleName, gojenkins.GlobalPermissionIds{ + GlobalRead: true, + }, true) + if err != nil { + glog.Errorf("failed to create jenkins global role %+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + } + err = globalRole.AssignRole(member.Username) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + projectRole, err := jenkinsClinet.GetProjectRole(GetProjectRoleName(projectId, member.Role)) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + err = projectRole.AssignRole(member.Username) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + pipelineRole, err := jenkinsClinet.GetProjectRole(GetPipelineRoleName(projectId, member.Role)) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + err = pipelineRole.AssignRole(member.Username) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + projectMembership := NewDevOpsProjectMemberShip(member.Username, projectId, member.Role, operator) + _, err = dbconn. + InsertInto(DevOpsProjectMembershipTableName). + Columns(DevOpsProjectMembershipColumns...). + Record(projectMembership).Exec() + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + return projectMembership, nil +} + +func UpdateProjectMember(projectId, operator string, member *DevOpsProjectMembership) (*DevOpsProjectMembership, error) { + dbconn := devops_mysql.OpenDatabase() + jenkinsClinet := admin_jenkins.Client() + oldMembership := &DevOpsProjectMembership{} + err := dbconn.Select(DevOpsProjectMembershipColumns...). + From(DevOpsProjectMembershipTableName). + Where(db.And( + db.Eq(DevOpsProjectMembershipUsernameColumn, member.Username), + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId), + )).LoadOne(oldMembership) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusBadRequest, err.Error()) + } + + oldProjectRole, err := jenkinsClinet.GetProjectRole(GetProjectRoleName(projectId, oldMembership.Role)) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + err = oldProjectRole.UnAssignRole(member.Username) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + oldPipelineRole, err := jenkinsClinet.GetProjectRole(GetPipelineRoleName(projectId, oldMembership.Role)) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + err = oldPipelineRole.UnAssignRole(member.Username) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + + projectRole, err := jenkinsClinet.GetProjectRole(GetProjectRoleName(projectId, member.Role)) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + err = projectRole.AssignRole(member.Username) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + pipelineRole, err := jenkinsClinet.GetProjectRole(GetPipelineRoleName(projectId, member.Role)) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + err = pipelineRole.AssignRole(member.Username) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(stringutils.GetJenkinsStatusCode(err), err.Error()) + } + _, err = dbconn.Update(DevOpsProjectMembershipTableName). + Set(DevOpsProjectMembershipRoleColumn, member.Role). + Where(db.And( + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId), + db.Eq(DevOpsProjectMembershipUsernameColumn, member.Username), + )).Exec() + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + responseMembership := &DevOpsProjectMembership{} + err = dbconn.Select(DevOpsProjectMembershipColumns...). + From(DevOpsProjectMembershipTableName). + Where(db.And( + db.Eq(DevOpsProjectMembershipUsernameColumn, member.Username), + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId), + )).LoadOne(responseMembership) + if err != nil { + glog.Errorf("%+v", err) + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) + } + return responseMembership, nil +} + +func DeleteProjectMember(projectId, username string) (string, error) { + dbconn := devops_mysql.OpenDatabase() + jenkinsClient := admin_jenkins.Client() + oldMembership := &DevOpsProjectMembership{} + err := dbconn.Select(DevOpsProjectMembershipColumns...). + From(DevOpsProjectMembershipTableName). + Where(db.And( + db.Eq(DevOpsProjectMembershipUsernameColumn, username), + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId), + )).LoadOne(oldMembership) + if err != nil && err != db.ErrNotFound { + glog.Errorf("%+v", err) + return "", restful.NewError(http.StatusInternalServerError, err.Error()) + } + if err == db.ErrNotFound { + glog.Warningf("user [%s] not found in project", username) + return username, nil + } + if oldMembership.Role == ProjectOwner { + count, err := dbconn.Select(DevOpsProjectMembershipProjectIdColumn). + From(DevOpsProjectMembershipTableName). + Where(db.And( + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId), + db.Eq(DevOpsProjectMembershipRoleColumn, ProjectOwner))).Count() + if err != nil { + glog.Errorf("%+v", err) + return "", restful.NewError(http.StatusInternalServerError, err.Error()) + } + if count == 1 { + err = fmt.Errorf("project must has at least one admin") + glog.Errorf("%+v", err) + return "", restful.NewError(http.StatusBadRequest, err.Error()) + } + } + oldProjectRole, err := jenkinsClient.GetProjectRole(GetProjectRoleName(projectId, oldMembership.Role)) + if err != nil { + glog.Errorf("%+v", err) + return "", restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) + } + err = oldProjectRole.UnAssignRole(username) + if err != nil { + glog.Errorf("%+v", err) + return "", restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) + } + + oldPipelineRole, err := jenkinsClient.GetProjectRole(GetPipelineRoleName(projectId, oldMembership.Role)) + if err != nil { + glog.Errorf("%+v", err) + return "", restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) + } + err = oldPipelineRole.UnAssignRole(username) + if err != nil { + glog.Errorf("%+v", err) + return "", restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) + } + + _, err = dbconn.DeleteFrom(DevOpsProjectMembershipTableName). + Where(db.And( + db.Eq(DevOpsProjectMembershipProjectIdColumn, projectId), + db.Eq(DevOpsProjectMembershipUsernameColumn, username), + )).Exec() + if err != nil { + glog.Errorf("%+v", err) + return "", restful.NewError(http.StatusInternalServerError, err.Error()) + } + return username, nil +} diff --git a/pkg/models/tenant/devops.go b/pkg/models/tenant/devops.go index 683361bde..85edf5540 100644 --- a/pkg/models/tenant/devops.go +++ b/pkg/models/tenant/devops.go @@ -19,6 +19,7 @@ package tenant import ( "fmt" + "github.com/emicklei/go-restful" "github.com/gocraft/dbr" "github.com/golang/glog" "kubesphere.io/kubesphere/pkg/db" @@ -29,248 +30,15 @@ import ( "kubesphere.io/kubesphere/pkg/params" "kubesphere.io/kubesphere/pkg/simple/client/admin_jenkins" "kubesphere.io/kubesphere/pkg/simple/client/devops_mysql" - "kubesphere.io/kubesphere/pkg/utils/reflectutils" "net/http" "sync" ) -const ( - ProjectOwner = "owner" - ProjectMaintainer = "maintainer" - ProjectDeveloper = "developer" - ProjectReporter = "reporter" -) - -var AllRoleSlice = []string{ProjectDeveloper, ProjectReporter, ProjectMaintainer, ProjectOwner} - -var JenkinsOwnerProjectPermissionIds = &gojenkins.ProjectPermissionIds{ - CredentialCreate: true, - CredentialDelete: true, - CredentialManageDomains: true, - CredentialUpdate: true, - CredentialView: true, - ItemBuild: true, - ItemCancel: true, - ItemConfigure: true, - ItemCreate: true, - ItemDelete: true, - ItemDiscover: true, - ItemMove: true, - ItemRead: true, - ItemWorkspace: true, - RunDelete: true, - RunReplay: true, - RunUpdate: true, - SCMTag: true, -} - -var JenkinsProjectPermissionMap = map[string]gojenkins.ProjectPermissionIds{ - ProjectOwner: gojenkins.ProjectPermissionIds{ - CredentialCreate: true, - CredentialDelete: true, - CredentialManageDomains: true, - CredentialUpdate: true, - CredentialView: true, - ItemBuild: true, - ItemCancel: true, - ItemConfigure: true, - ItemCreate: true, - ItemDelete: true, - ItemDiscover: true, - ItemMove: true, - ItemRead: true, - ItemWorkspace: true, - RunDelete: true, - RunReplay: true, - RunUpdate: true, - SCMTag: true, - }, - ProjectMaintainer: gojenkins.ProjectPermissionIds{ - CredentialCreate: true, - CredentialDelete: true, - CredentialManageDomains: true, - CredentialUpdate: true, - CredentialView: true, - ItemBuild: true, - ItemCancel: true, - ItemConfigure: false, - ItemCreate: true, - ItemDelete: false, - ItemDiscover: true, - ItemMove: false, - ItemRead: true, - ItemWorkspace: true, - RunDelete: true, - RunReplay: true, - RunUpdate: true, - SCMTag: true, - }, - ProjectDeveloper: gojenkins.ProjectPermissionIds{ - CredentialCreate: false, - CredentialDelete: false, - CredentialManageDomains: false, - CredentialUpdate: false, - CredentialView: false, - ItemBuild: true, - ItemCancel: true, - ItemConfigure: false, - ItemCreate: false, - ItemDelete: false, - ItemDiscover: true, - ItemMove: false, - ItemRead: true, - ItemWorkspace: true, - RunDelete: true, - RunReplay: true, - RunUpdate: true, - SCMTag: false, - }, - ProjectReporter: gojenkins.ProjectPermissionIds{ - CredentialCreate: false, - CredentialDelete: false, - CredentialManageDomains: false, - CredentialUpdate: false, - CredentialView: false, - ItemBuild: false, - ItemCancel: false, - ItemConfigure: false, - ItemCreate: false, - ItemDelete: false, - ItemDiscover: true, - ItemMove: false, - ItemRead: true, - ItemWorkspace: false, - RunDelete: false, - RunReplay: false, - RunUpdate: false, - SCMTag: false, - }, -} - -var JenkinsPipelinePermissionMap = map[string]gojenkins.ProjectPermissionIds{ - ProjectOwner: gojenkins.ProjectPermissionIds{ - CredentialCreate: true, - CredentialDelete: true, - CredentialManageDomains: true, - CredentialUpdate: true, - CredentialView: true, - ItemBuild: true, - ItemCancel: true, - ItemConfigure: true, - ItemCreate: true, - ItemDelete: true, - ItemDiscover: true, - ItemMove: true, - ItemRead: true, - ItemWorkspace: true, - RunDelete: true, - RunReplay: true, - RunUpdate: true, - SCMTag: true, - }, - ProjectMaintainer: gojenkins.ProjectPermissionIds{ - CredentialCreate: true, - CredentialDelete: true, - CredentialManageDomains: true, - CredentialUpdate: true, - CredentialView: true, - ItemBuild: true, - ItemCancel: true, - ItemConfigure: true, - ItemCreate: true, - ItemDelete: true, - ItemDiscover: true, - ItemMove: true, - ItemRead: true, - ItemWorkspace: true, - RunDelete: true, - RunReplay: true, - RunUpdate: true, - SCMTag: true, - }, - ProjectDeveloper: gojenkins.ProjectPermissionIds{ - CredentialCreate: false, - CredentialDelete: false, - CredentialManageDomains: false, - CredentialUpdate: false, - CredentialView: false, - ItemBuild: true, - ItemCancel: true, - ItemConfigure: false, - ItemCreate: false, - ItemDelete: false, - ItemDiscover: true, - ItemMove: false, - ItemRead: true, - ItemWorkspace: true, - RunDelete: true, - RunReplay: true, - RunUpdate: true, - SCMTag: false, - }, - ProjectReporter: gojenkins.ProjectPermissionIds{ - CredentialCreate: false, - CredentialDelete: false, - CredentialManageDomains: false, - CredentialUpdate: false, - CredentialView: false, - ItemBuild: false, - ItemCancel: false, - ItemConfigure: false, - ItemCreate: false, - ItemDelete: false, - ItemDiscover: true, - ItemMove: false, - ItemRead: true, - ItemWorkspace: false, - RunDelete: false, - RunReplay: false, - RunUpdate: false, - SCMTag: false, - }, -} - -func GetProjectRoleName(projectId, role string) string { - return fmt.Sprintf("%s-%s-project", projectId, role) -} - -func GetPipelineRoleName(projectId, role string) string { - return fmt.Sprintf("%s-%s-pipeline", projectId, role) -} - -func GetProjectRolePattern(projectId string) string { - return fmt.Sprintf("^%s$", projectId) -} - -func GetPipelineRolePattern(projectId string) string { - return fmt.Sprintf("^%s/.*", projectId) -} - type DevOpsProjectRoleResponse struct { ProjectRole *gojenkins.ProjectRole Err error } -func CheckProjectUserInRole(username, projectId string, roles []string) error { - if username == devops.KS_ADMIN { - return nil - } - dbconn := devops_mysql.OpenDatabase() - membership := &devops.DevOpsProjectMembership{} - err := dbconn.Select(devops.DevOpsProjectMembershipColumns...). - From(devops.DevOpsProjectMembershipTableName). - Where(db.And( - db.Eq(devops.DevOpsProjectMembershipUsernameColumn, username), - db.Eq(devops.DevOpsProjectMembershipProjectIdColumn, projectId))).LoadOne(membership) - if err != nil { - return err - } - if !reflectutils.In(membership.Role, roles) { - return fmt.Errorf("user [%s] in project [%s] role is not in %s", username, projectId, roles) - } - return nil -} - func ListDevopsProjects(workspace, username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) { dbconn := devops_mysql.OpenDatabase() @@ -321,12 +89,12 @@ func ListDevopsProjects(workspace, username string, conditions *params.Condition _, err := query.Load(&projects) if err != nil { glog.Errorf("%+v", err) - return nil, err + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) } count, err := query.Count() if err != nil { glog.Errorf("%+v", err) - return nil, err + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) } result := make([]interface{}, 0) @@ -337,11 +105,11 @@ func ListDevopsProjects(workspace, username string, conditions *params.Condition return &models.PageableResponse{Items: result, TotalCount: int(count)}, nil } -func DeleteDevOpsProject(projectId, username string) (error, int) { - err := CheckProjectUserInRole(username, projectId, []string{ProjectOwner}) +func DeleteDevOpsProject(projectId, username string) error { + err := devops.CheckProjectUserInRole(username, projectId, []string{devops.ProjectOwner}) if err != nil { glog.Errorf("%+v", err) - return err, http.StatusForbidden + return restful.NewError(http.StatusForbidden, err.Error()) } gojenkins := admin_jenkins.Client() devopsdb := devops_mysql.OpenDatabase() @@ -349,31 +117,31 @@ func DeleteDevOpsProject(projectId, username string) (error, int) { if err != nil && utils.GetJenkinsStatusCode(err) != http.StatusNotFound { glog.Errorf("%+v", err) - return err, utils.GetJenkinsStatusCode(err) + return restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } roleNames := make([]string, 0) - for role := range JenkinsProjectPermissionMap { - roleNames = append(roleNames, GetProjectRoleName(projectId, role)) - roleNames = append(roleNames, GetPipelineRoleName(projectId, role)) + for role := range devops.JenkinsProjectPermissionMap { + roleNames = append(roleNames, devops.GetProjectRoleName(projectId, role)) + roleNames = append(roleNames, devops.GetPipelineRoleName(projectId, role)) } err = gojenkins.DeleteProjectRoles(roleNames...) if err != nil { glog.Errorf("%+v", err) - return err, utils.GetJenkinsStatusCode(err) + return restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } _, err = devopsdb.DeleteFrom(devops.DevOpsProjectMembershipTableName). Where(db.Eq(devops.DevOpsProjectMembershipProjectIdColumn, projectId)).Exec() if err != nil { glog.Errorf("%+v", err) - return err, http.StatusInternalServerError + return restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } _, err = devopsdb.Update(devops.DevOpsProjectTableName). Set(devops.StatusColumn, devops.StatusDeleted). Where(db.Eq(devops.DevOpsProjectIdColumn, projectId)).Exec() if err != nil { glog.Errorf("%+v", err) - return err, http.StatusInternalServerError + return restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } project := &devops.DevOpsProject{} err = devopsdb.Select(devops.DevOpsProjectColumns...). @@ -382,12 +150,12 @@ func DeleteDevOpsProject(projectId, username string) (error, int) { LoadOne(project) if err != nil { glog.Errorf("%+v", err) - return err, http.StatusInternalServerError + return restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } - return nil, http.StatusOK + return nil } -func CreateDevopsProject(username string, workspace string, req *devops.DevOpsProject) (*devops.DevOpsProject, error, int) { +func CreateDevopsProject(username string, workspace string, req *devops.DevOpsProject) (*devops.DevOpsProject, error) { jenkinsClient := admin_jenkins.Client() devopsdb := devops_mysql.OpenDatabase() @@ -395,25 +163,25 @@ func CreateDevopsProject(username string, workspace string, req *devops.DevOpsPr _, err := jenkinsClient.CreateFolder(project.ProjectId, project.Description) if err != nil { glog.Errorf("%+v", err) - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } var addRoleCh = make(chan *DevOpsProjectRoleResponse, 8) var addRoleWg sync.WaitGroup - for role, permission := range JenkinsProjectPermissionMap { + for role, permission := range devops.JenkinsProjectPermissionMap { addRoleWg.Add(1) go func(role string, permission gojenkins.ProjectPermissionIds) { - _, err := jenkinsClient.AddProjectRole(GetProjectRoleName(project.ProjectId, role), - GetProjectRolePattern(project.ProjectId), permission, true) + _, err := jenkinsClient.AddProjectRole(devops.GetProjectRoleName(project.ProjectId, role), + devops.GetProjectRolePattern(project.ProjectId), permission, true) addRoleCh <- &DevOpsProjectRoleResponse{nil, err} addRoleWg.Done() }(role, permission) } - for role, permission := range JenkinsPipelinePermissionMap { + for role, permission := range devops.JenkinsPipelinePermissionMap { addRoleWg.Add(1) go func(role string, permission gojenkins.ProjectPermissionIds) { - _, err := jenkinsClient.AddProjectRole(GetPipelineRoleName(project.ProjectId, role), - GetPipelineRolePattern(project.ProjectId), permission, true) + _, err := jenkinsClient.AddProjectRole(devops.GetPipelineRoleName(project.ProjectId, role), + devops.GetPipelineRolePattern(project.ProjectId), permission, true) addRoleCh <- &DevOpsProjectRoleResponse{nil, err} addRoleWg.Done() }(role, permission) @@ -423,14 +191,14 @@ func CreateDevopsProject(username string, workspace string, req *devops.DevOpsPr for addRoleResponse := range addRoleCh { if addRoleResponse.Err != nil { glog.Errorf("%+v", addRoleResponse.Err) - return nil, addRoleResponse.Err, utils.GetJenkinsStatusCode(addRoleResponse.Err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(addRoleResponse.Err), addRoleResponse.Err.Error()) } } globalRole, err := jenkinsClient.GetGlobalRole(devops.JenkinsAllUserRoleName) if err != nil { glog.Errorf("%+v", err) - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } if globalRole == nil { _, err := jenkinsClient.AddGlobalRole(devops.JenkinsAllUserRoleName, gojenkins.GlobalPermissionIds{ @@ -438,58 +206,58 @@ func CreateDevopsProject(username string, workspace string, req *devops.DevOpsPr }, true) if err != nil { glog.Error("failed to create jenkins global role") - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } } err = globalRole.AssignRole(username) if err != nil { glog.Errorf("%+v", err) - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } - projectRole, err := jenkinsClient.GetProjectRole(GetProjectRoleName(project.ProjectId, ProjectOwner)) + projectRole, err := jenkinsClient.GetProjectRole(devops.GetProjectRoleName(project.ProjectId, devops.ProjectOwner)) if err != nil { glog.Errorf("%+v", err) - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } err = projectRole.AssignRole(username) if err != nil { glog.Errorf("%+v", err) - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } - pipelineRole, err := jenkinsClient.GetProjectRole(GetPipelineRoleName(project.ProjectId, ProjectOwner)) + pipelineRole, err := jenkinsClient.GetProjectRole(devops.GetPipelineRoleName(project.ProjectId, devops.ProjectOwner)) if err != nil { glog.Errorf("%+v", err) - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } err = pipelineRole.AssignRole(username) if err != nil { glog.Errorf("%+v", err) - return nil, err, utils.GetJenkinsStatusCode(err) + return nil, restful.NewError(utils.GetJenkinsStatusCode(err), err.Error()) } _, err = devopsdb.InsertInto(devops.DevOpsProjectTableName). Columns(devops.DevOpsProjectColumns...).Record(project).Exec() if err != nil { glog.Errorf("%+v", err) - return nil, err, http.StatusInternalServerError + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) } - projectMembership := devops.NewDevOpsProjectMemberShip(username, project.ProjectId, ProjectOwner, username) + projectMembership := devops.NewDevOpsProjectMemberShip(username, project.ProjectId, devops.ProjectOwner, username) _, err = devopsdb.InsertInto(devops.DevOpsProjectMembershipTableName). Columns(devops.DevOpsProjectMembershipColumns...).Record(projectMembership).Exec() if err != nil { glog.Errorf("%+v", err) - return nil, err, http.StatusInternalServerError + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) } - return project, nil, http.StatusOK + return project, nil } -func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error, int) { - err := CheckProjectUserInRole(username, projectId, AllRoleSlice) +func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error) { + err := devops.CheckProjectUserInRole(username, projectId, devops.AllRoleSlice) if err != nil { glog.Errorf("%+v", err) - return nil, err, http.StatusForbidden + return nil, restful.NewError(http.StatusForbidden, err.Error()) } dbconn := devops_mysql.OpenDatabase() memberships := &devops.DevOpsProjectMembership{} @@ -502,10 +270,10 @@ func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, if err != nil { glog.Errorf("%+v", err) - return nil, err, http.StatusInternalServerError + return nil, restful.NewError(http.StatusInternalServerError, err.Error()) } - return GetDevopsRoleSimpleRules(memberships.Role), nil, http.StatusOK + return GetDevopsRoleSimpleRules(memberships.Role), nil } func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {