@@ -254,6 +254,12 @@ func (c *Controller) syncHandler(key string) error {
|
|||||||
ns := c.generateNewNamespace(project)
|
ns := c.generateNewNamespace(project)
|
||||||
ns, err := c.client.CoreV1().Namespaces().Create(ns)
|
ns, err := c.client.CoreV1().Namespaces().Create(ns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// devops project name is conflict, cannot create admin namespace
|
||||||
|
if errors.IsAlreadyExists(err) {
|
||||||
|
klog.Errorf("Failed to create admin namespace for devopsproject %s, error %v", project.Name, err)
|
||||||
|
c.eventRecorder.Event(project, v1.EventTypeWarning, "CreateAdminNamespaceFailed", err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
klog.V(8).Info(err, fmt.Sprintf("failed to create ns %s ", key))
|
klog.V(8).Info(err, fmt.Sprintf("failed to create ns %s ", key))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -369,13 +375,15 @@ func (c *Controller) deleteDevOpsProjectInDevOps(project *devopsv1alpha3.DevOpsP
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) generateNewNamespace(project *devopsv1alpha3.DevOpsProject) *v1.Namespace {
|
func (c *Controller) generateNewNamespace(project *devopsv1alpha3.DevOpsProject) *v1.Namespace {
|
||||||
|
// devops project name and admin namespace name should be the same
|
||||||
|
// solve the access control problem of devops API v1alpha2 and v1alpha3
|
||||||
ns := &v1.Namespace{
|
ns := &v1.Namespace{
|
||||||
TypeMeta: metav1.TypeMeta{
|
TypeMeta: metav1.TypeMeta{
|
||||||
Kind: "Namespace",
|
Kind: "Namespace",
|
||||||
APIVersion: v1.SchemeGroupVersion.String(),
|
APIVersion: v1.SchemeGroupVersion.String(),
|
||||||
},
|
},
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
GenerateName: project.Name,
|
Name: project.Name,
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
constants.DevOpsProjectLabelKey: project.Name,
|
constants.DevOpsProjectLabelKey: project.Name,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -371,13 +371,13 @@ func TestUpdateNsOwnerReference(t *testing.T) {
|
|||||||
func TestCreateDevOpsProjects(t *testing.T) {
|
func TestCreateDevOpsProjects(t *testing.T) {
|
||||||
f := newFixture(t)
|
f := newFixture(t)
|
||||||
project := newDevOpsProject("test", "", true, false)
|
project := newDevOpsProject("test", "", true, false)
|
||||||
ns := newNamespace("test-123", "test", true, true)
|
ns := newNamespace("test", "test", false, true)
|
||||||
f.devopsProjectLister = append(f.devopsProjectLister, project)
|
f.devopsProjectLister = append(f.devopsProjectLister, project)
|
||||||
f.objects = append(f.objects, project)
|
f.objects = append(f.objects, project)
|
||||||
f.expectDevOpsProject = []string{""}
|
f.expectDevOpsProject = []string{""}
|
||||||
|
expect := project.DeepCopy()
|
||||||
// because generateName not work in fakeClient, so DevOpsProject would not be update
|
expect.Status.AdminNamespace = "test"
|
||||||
// f.expectUpdateDevOpsProjectAction(project)
|
f.expectUpdateDevOpsProjectAction(expect)
|
||||||
f.expectCreateNamespaceAction(ns)
|
f.expectCreateNamespaceAction(ns)
|
||||||
f.run(getKey(project, t))
|
f.run(getKey(project, t))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,9 @@ func (h *devopsHandler) CreateDevOpsProject(request *restful.Request, response *
|
|||||||
if errors.IsNotFound(err) {
|
if errors.IsNotFound(err) {
|
||||||
api.HandleNotFound(response, request, err)
|
api.HandleNotFound(response, request, err)
|
||||||
return
|
return
|
||||||
|
} else if errors.IsConflict(err) {
|
||||||
|
api.HandleConflict(response, request, err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1222,7 +1222,7 @@ func (h *iamHandler) ListUserLoginRecords(request *restful.Request, response *re
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleError(request *restful.Request, response *restful.Response, err error) {
|
func handleError(request *restful.Request, response *restful.Response, err error) {
|
||||||
if errors.IsBadRequest(err) {
|
if errors.IsBadRequest(err) || errors.IsInvalid(err) {
|
||||||
api.HandleBadRequest(response, request, err)
|
api.HandleBadRequest(response, request, err)
|
||||||
} else if errors.IsNotFound(err) {
|
} else if errors.IsNotFound(err) {
|
||||||
api.HandleNotFound(response, request, err)
|
api.HandleNotFound(response, request, err)
|
||||||
|
|||||||
@@ -23,13 +23,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"kubesphere.io/kubesphere/pkg/api"
|
"kubesphere.io/kubesphere/pkg/api"
|
||||||
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
"kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
||||||
|
devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3"
|
||||||
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||||
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
kubesphere "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
|
||||||
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
|
||||||
@@ -143,7 +146,30 @@ func convertToHttpParameters(req *http.Request) *devops.HttpParameters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d devopsOperator) CreateDevOpsProject(workspace string, project *v1alpha3.DevOpsProject) (*v1alpha3.DevOpsProject, error) {
|
func (d devopsOperator) CreateDevOpsProject(workspace string, project *v1alpha3.DevOpsProject) (*v1alpha3.DevOpsProject, error) {
|
||||||
project.Annotations[tenantv1alpha1.WorkspaceLabel] = workspace
|
// All resources of devops project belongs to the namespace of the same name
|
||||||
|
// The devops project name is used as the name of the admin namespace, using generateName to avoid conflicts
|
||||||
|
if project.GenerateName == "" {
|
||||||
|
err := errors.NewInvalid(devopsv1alpha3.SchemeGroupVersion.WithKind(devopsv1alpha3.ResourceKindDevOpsProject).GroupKind(),
|
||||||
|
"", []*field.Error{field.Required(field.NewPath("metadata.generateName"), "generateName is required")})
|
||||||
|
klog.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// generateName is used as displayName
|
||||||
|
// ensure generateName is unique in workspace scope
|
||||||
|
if unique, err := d.isGenerateNameUnique(workspace, project.GenerateName); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !unique {
|
||||||
|
err = errors.NewConflict(devopsv1alpha3.Resource(devopsv1alpha3.ResourceSingularDevOpsProject),
|
||||||
|
project.GenerateName, fmt.Errorf(project.GenerateName, fmt.Errorf("a devops project named %s already exists in the workspace", project.GenerateName)))
|
||||||
|
klog.Error(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// metadata override
|
||||||
|
if project.Labels == nil {
|
||||||
|
project.Labels = make(map[string]string, 0)
|
||||||
|
}
|
||||||
|
project.Name = ""
|
||||||
|
project.Labels[tenantv1alpha1.WorkspaceLabel] = workspace
|
||||||
return d.ksclient.DevopsV1alpha3().DevOpsProjects().Create(project)
|
return d.ksclient.DevopsV1alpha3().DevOpsProjects().Create(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +182,10 @@ func (d devopsOperator) DeleteDevOpsProject(workspace string, projectName string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d devopsOperator) UpdateDevOpsProject(workspace string, project *v1alpha3.DevOpsProject) (*v1alpha3.DevOpsProject, error) {
|
func (d devopsOperator) UpdateDevOpsProject(workspace string, project *v1alpha3.DevOpsProject) (*v1alpha3.DevOpsProject, error) {
|
||||||
project.Annotations[tenantv1alpha1.WorkspaceLabel] = workspace
|
if project.Labels == nil {
|
||||||
|
project.Labels = make(map[string]string, 0)
|
||||||
|
}
|
||||||
|
project.Labels[tenantv1alpha1.WorkspaceLabel] = workspace
|
||||||
return d.ksclient.DevopsV1alpha3().DevOpsProjects().Update(project)
|
return d.ksclient.DevopsV1alpha3().DevOpsProjects().Update(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,6 +895,21 @@ func (d devopsOperator) ToJson(req *http.Request) (*devops.ResJson, error) {
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d devopsOperator) isGenerateNameUnique(workspace, generateName string) (bool, error) {
|
||||||
|
selector := labels.Set{tenantv1alpha1.WorkspaceLabel: workspace}
|
||||||
|
projects, err := d.ksInformers.Devops().V1alpha3().DevOpsProjects().Lister().List(labels.SelectorFromSet(selector))
|
||||||
|
if err != nil {
|
||||||
|
klog.Error(err)
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for _, p := range projects {
|
||||||
|
if p.GenerateName == generateName {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
func getInputReqBody(reqBody io.ReadCloser) (newReqBody io.ReadCloser, err error) {
|
func getInputReqBody(reqBody io.ReadCloser) (newReqBody io.ReadCloser, err error) {
|
||||||
var checkBody devops.CheckPlayload
|
var checkBody devops.CheckPlayload
|
||||||
var jsonBody []byte
|
var jsonBody []byte
|
||||||
|
|||||||
Reference in New Issue
Block a user