add devops project controller

Signed-off-by: runzexia <runzexia@yunify.com>
This commit is contained in:
runzexia
2020-03-18 14:48:41 +08:00
parent 0a07e5f652
commit 93461cfb0b
40 changed files with 1487 additions and 225 deletions

View File

@@ -1,5 +1,12 @@
package devops
import (
"fmt"
"github.com/asaskevich/govalidator"
"net/http"
"strconv"
)
type Interface interface {
CredentialOperator
@@ -10,4 +17,30 @@ type Interface interface {
ProjectMemberOperator
ProjectPipelineOperator
ProjectOperator
}
func GetDevOpsStatusCode(devopsErr error) int {
if code, err := strconv.Atoi(devopsErr.Error()); err == nil {
message := http.StatusText(code)
if !govalidator.IsNull(message) {
return code
}
}
if jErr, ok := devopsErr.(*ErrorResponse); ok {
return jErr.Response.StatusCode
}
return http.StatusInternalServerError
}
type ErrorResponse struct {
Body []byte
Response *http.Response
Message string
}
func (e *ErrorResponse) Error() string {
u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, e.Response.Request.URL.RequestURI())
return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message)
}

View File

@@ -399,7 +399,7 @@ func (b *Build) Poll(options ...interface{}) (int, error) {
func (j *Jenkins) GetProjectPipelineBuildByType(projectId, pipelineId string, status string) (*devops.Build, error) {
job, err := j.GetJob(pipelineId, projectId)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
build, err := job.getBuildByType(status)
return build.Raw, nil
@@ -407,7 +407,7 @@ func (j *Jenkins) GetProjectPipelineBuildByType(projectId, pipelineId string, st
func (j *Jenkins) GetMultiBranchPipelineBuildByType(projectId, pipelineId, branch string, status string) (*devops.Build, error) {
job, err := j.GetJob(pipelineId, projectId, branch)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
build, err := job.getBuildByType(status)
return build.Raw, nil

View File

@@ -218,7 +218,7 @@ func (j *Jenkins) AddProjectMember(membership *devops.ProjectMembership) (*devop
globalRole, err := j.GetGlobalRole(JenkinsAllUserRoleName)
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
if globalRole == nil {
_, err := j.AddGlobalRole(JenkinsAllUserRoleName, GlobalPermissionIds{
@@ -226,33 +226,33 @@ func (j *Jenkins) AddProjectMember(membership *devops.ProjectMembership) (*devop
}, true)
if err != nil {
klog.Errorf("failed to create jenkins global role %+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
}
err = globalRole.AssignRole(membership.Username)
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
projectRole, err := j.GetProjectRole(GetProjectRoleName(membership.ProjectId, membership.Role))
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = projectRole.AssignRole(membership.Username)
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
pipelineRole, err := j.GetProjectRole(GetPipelineRoleName(membership.ProjectId, membership.Role))
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = pipelineRole.AssignRole(membership.Username)
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return membership, nil
}
@@ -260,42 +260,42 @@ func (j *Jenkins) AddProjectMember(membership *devops.ProjectMembership) (*devop
func (j *Jenkins) UpdateProjectMember(oldMembership, newMembership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
oldProjectRole, err := j.GetProjectRole(GetProjectRoleName(oldMembership.ProjectId, oldMembership.Role))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = oldProjectRole.UnAssignRole(newMembership.Username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
oldPipelineRole, err := j.GetProjectRole(GetPipelineRoleName(oldMembership.ProjectId, oldMembership.Role))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = oldPipelineRole.UnAssignRole(newMembership.Username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
projectRole, err := j.GetProjectRole(GetProjectRoleName(oldMembership.ProjectId, newMembership.Role))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = projectRole.AssignRole(newMembership.Username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
pipelineRole, err := j.GetProjectRole(GetPipelineRoleName(oldMembership.ProjectId, newMembership.Role))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = pipelineRole.AssignRole(newMembership.Username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return newMembership, nil
}
@@ -303,20 +303,20 @@ func (j *Jenkins) UpdateProjectMember(oldMembership, newMembership *devops.Proje
func (j *Jenkins) DeleteProjectMember(membership *devops.ProjectMembership) (*devops.ProjectMembership, error) {
oldProjectRole, err := j.GetProjectRole(GetProjectRoleName(membership.ProjectId, membership.Role))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = oldProjectRole.UnAssignRole(membership.Username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
oldPipelineRole, err := j.GetProjectRole(GetPipelineRoleName(membership.ProjectId, membership.Role))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = oldPipelineRole.UnAssignRole(membership.Username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return membership, nil
}

View File

@@ -3,10 +3,8 @@ package jenkins
import (
"github.com/emicklei/go-restful"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
"kubesphere.io/kubesphere/pkg/simple/client/devops"
"net/http"
"sync"
)
type DevOpsProjectRoleResponse struct {
@@ -14,96 +12,31 @@ type DevOpsProjectRoleResponse struct {
Err error
}
func (j *Jenkins) CreateDevOpsProject(username string, project *v1alpha2.DevOpsProject) (*v1alpha2.DevOpsProject, error) {
_, err := j.CreateFolder(project.ProjectId, project.Description)
func (j *Jenkins) CreateDevOpsProject(projectId string) (string, error) {
_, err := j.CreateFolder(projectId, "")
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
var addRoleCh = make(chan *DevOpsProjectRoleResponse, 8)
var addRoleWg sync.WaitGroup
for role, permission := range JenkinsProjectPermissionMap {
addRoleWg.Add(1)
go func(role string, permission ProjectPermissionIds) {
_, err := j.AddProjectRole(GetProjectRoleName(project.ProjectId, role),
GetProjectRolePattern(project.ProjectId), permission, true)
addRoleCh <- &DevOpsProjectRoleResponse{nil, err}
addRoleWg.Done()
}(role, permission)
}
for role, permission := range JenkinsPipelinePermissionMap {
addRoleWg.Add(1)
go func(role string, permission ProjectPermissionIds) {
_, err := j.AddProjectRole(GetPipelineRoleName(project.ProjectId, role),
GetPipelineRolePattern(project.ProjectId), permission, true)
addRoleCh <- &DevOpsProjectRoleResponse{nil, err}
addRoleWg.Done()
}(role, permission)
}
addRoleWg.Wait()
close(addRoleCh)
for addRoleResponse := range addRoleCh {
if addRoleResponse.Err != nil {
klog.Errorf("%+v", addRoleResponse.Err)
return nil, restful.NewError(GetJenkinsStatusCode(addRoleResponse.Err), addRoleResponse.Err.Error())
}
}
globalRole, err := j.GetGlobalRole(JenkinsAllUserRoleName)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
if globalRole == nil {
_, err := j.AddGlobalRole(JenkinsAllUserRoleName, GlobalPermissionIds{
GlobalRead: true,
}, true)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
}
err = globalRole.AssignRole(username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
projectRole, err := j.GetProjectRole(GetProjectRoleName(project.ProjectId, devops.ProjectOwner))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
err = projectRole.AssignRole(username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
pipelineRole, err := j.GetProjectRole(GetPipelineRoleName(project.ProjectId, devops.ProjectOwner))
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
err = pipelineRole.AssignRole(username)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
return project, nil
return projectId, nil
}
func (j *Jenkins) DeleteDevOpsProject(projectId string) error {
_, err := j.DeleteJob(projectId)
if err != nil && GetJenkinsStatusCode(err) != http.StatusNotFound {
if err != nil && devops.GetDevOpsStatusCode(err) != http.StatusNotFound {
klog.Errorf("%+v", err)
return restful.NewError(GetJenkinsStatusCode(err), err.Error())
}
roleNames := make([]string, 0)
for role := range JenkinsProjectPermissionMap {
roleNames = append(roleNames, GetProjectRoleName(projectId, role))
roleNames = append(roleNames, GetPipelineRoleName(projectId, role))
}
err = j.DeleteProjectRoles(roleNames...)
if err != nil {
klog.Errorf("%+v", err)
return restful.NewError(GetJenkinsStatusCode(err), err.Error())
return restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return nil
}
func (j *Jenkins) GetDevOpsProject(projectId string) (string, error) {
job, err := j.GetJob(projectId)
if err != nil {
klog.Errorf("%+v", err)
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return job.GetName(), nil
}

View File

@@ -23,13 +23,13 @@ func (j *Jenkins) CreateProjectPipeline(projectId string, pipeline *devops.Proje
return "", restful.NewError(http.StatusConflict, err.Error())
}
if err != nil && GetJenkinsStatusCode(err) != http.StatusNotFound {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
if err != nil && devops.GetDevOpsStatusCode(err) != http.StatusNotFound {
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
_, err = j.CreateJobInFolder(config, pipeline.Pipeline.Name, projectId)
if err != nil {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return pipeline.Pipeline.Name, nil
@@ -45,13 +45,13 @@ func (j *Jenkins) CreateProjectPipeline(projectId string, pipeline *devops.Proje
return "", restful.NewError(http.StatusConflict, err.Error())
}
if err != nil && GetJenkinsStatusCode(err) != http.StatusNotFound {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
if err != nil && devops.GetDevOpsStatusCode(err) != http.StatusNotFound {
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
_, err = j.CreateJobInFolder(config, pipeline.MultiBranchPipeline.Name, projectId)
if err != nil {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return pipeline.MultiBranchPipeline.Name, nil
@@ -66,7 +66,7 @@ func (j *Jenkins) CreateProjectPipeline(projectId string, pipeline *devops.Proje
func (j *Jenkins) DeleteProjectPipeline(projectId string, pipelineId string) (string, error) {
_, err := j.DeleteJob(pipelineId, projectId)
if err != nil {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return pipelineId, nil
@@ -83,12 +83,12 @@ func (j *Jenkins) UpdateProjectPipeline(projectId string, pipeline *devops.Proje
job, err := j.GetJob(pipeline.Pipeline.Name, projectId)
if err != nil {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = job.UpdateConfig(config)
if err != nil {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return pipeline.Pipeline.Name, nil
@@ -104,13 +104,13 @@ func (j *Jenkins) UpdateProjectPipeline(projectId string, pipeline *devops.Proje
job, err := j.GetJob(pipeline.MultiBranchPipeline.Name, projectId)
if err != nil {
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
err = job.UpdateConfig(config)
if err != nil {
klog.Errorf("%+v", err)
return "", restful.NewError(GetJenkinsStatusCode(err), err.Error())
return "", restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
return pipeline.MultiBranchPipeline.Name, nil
@@ -126,17 +126,17 @@ func (j *Jenkins) GetProjectPipelineConfig(projectId, pipelineId string) (*devop
job, err := j.GetJob(pipelineId, projectId)
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
switch job.Raw.Class {
case "org.jenkinsci.plugins.workflow.job.WorkflowJob":
config, err := job.GetConfig()
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
pipeline, err := parsePipelineConfigXml(config)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
pipeline.Name = pipelineId
return &devops.ProjectPipeline{
@@ -147,11 +147,11 @@ func (j *Jenkins) GetProjectPipelineConfig(projectId, pipelineId string) (*devop
case "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject":
config, err := job.GetConfig()
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
pipeline, err := parseMultiBranchPipelineConfigXml(config)
if err != nil {
return nil, restful.NewError(GetJenkinsStatusCode(err), err.Error())
return nil, restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
}
pipeline.Name = pipelineId
return &devops.ProjectPipeline{

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"io"
"io/ioutil"
"kubesphere.io/kubesphere/pkg/simple/client/devops"
"mime/multipart"
"net/http"
"net/url"
@@ -64,7 +65,7 @@ func (r *Requester) SetCrumb(ar *APIRequest) error {
crumbData := map[string]string{}
response, err := r.GetJSON("/crumbIssuer/api/json", &crumbData, nil)
if err != nil {
jenkinsError, ok := err.(*ErrorResponse)
jenkinsError, ok := err.(*devops.ErrorResponse)
if ok && jenkinsError.Response.StatusCode == http.StatusNotFound {
return nil
}
@@ -440,16 +441,6 @@ func (r *Requester) ReadJSONResponse(response *http.Response, responseStruct int
return response, nil
}
type ErrorResponse struct {
Body []byte
Response *http.Response
Message string
}
func (e *ErrorResponse) Error() string {
u := fmt.Sprintf("%s://%s%s", e.Response.Request.URL.Scheme, e.Response.Request.URL.Host, e.Response.Request.URL.RequestURI())
return fmt.Sprintf("%s %s: %d %s", e.Response.Request.Method, u, e.Response.StatusCode, e.Message)
}
func CheckResponse(r *http.Response) error {
switch r.StatusCode {
@@ -457,7 +448,7 @@ func CheckResponse(r *http.Response) error {
return nil
}
defer r.Body.Close()
errorResponse := &ErrorResponse{Response: r}
errorResponse := &devops.ErrorResponse{Response: r}
data, err := ioutil.ReadAll(r.Body)
if err == nil && data != nil {
errorResponse.Body = data

View File

@@ -17,13 +17,11 @@ package jenkins
import (
"compress/gzip"
"encoding/json"
"github.com/asaskevich/govalidator"
"io"
"io/ioutil"
"k8s.io/klog"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"unicode/utf8"
@@ -131,16 +129,3 @@ func (t *JenkinsBlueTime) UnmarshalJSON(b []byte) error {
func (t JenkinsBlueTime) MarshalJSON() ([]byte, error) {
return json.Marshal(time.Time(t))
}
func GetJenkinsStatusCode(jenkinsErr error) int {
if code, err := strconv.Atoi(jenkinsErr.Error()); err == nil {
message := http.StatusText(code)
if !govalidator.IsNull(message) {
return code
}
}
if jErr, ok := jenkinsErr.(*ErrorResponse); ok {
return jErr.Response.StatusCode
}
return http.StatusInternalServerError
}

View File

@@ -1,8 +1,12 @@
package devops
import "kubesphere.io/kubesphere/pkg/api/devops/v1alpha2"
/**
project operator, providing API for creating/getting/deleting projects
The actual data of the project is stored in the CRD,
so we only need to create the project with the corresponding ID in the CI/CD system.
*/
type ProjectOperator interface {
CreateDevOpsProject(username string, project *v1alpha2.DevOpsProject) (*v1alpha2.DevOpsProject, error)
CreateDevOpsProject(projectId string) (string, error)
DeleteDevOpsProject(projectId string) error
GetDevOpsProject(projectId string) (string, error)
}