Fix devops project cannot be deleted due to mess up with finalizer control
Signed-off-by: rick <rick@jenkins-zh.cn>
This commit is contained in:
@@ -18,6 +18,7 @@ package devopsproject
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/emicklei/go-restful"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -41,6 +42,7 @@ import (
|
|||||||
devopsClient "kubesphere.io/kubesphere/pkg/simple/client/devops"
|
devopsClient "kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||||
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
|
||||||
"time"
|
"time"
|
||||||
@@ -213,13 +215,14 @@ func (c *Controller) syncHandler(key string) error {
|
|||||||
klog.V(8).Info(err, fmt.Sprintf("could not get devopsproject %s ", key))
|
klog.V(8).Info(err, fmt.Sprintf("could not get devopsproject %s ", key))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//If the sync is successful, return handle
|
|
||||||
if state, ok := project.Annotations[devopsv1alpha3.DevOpeProjectSyncStatusAnnoKey]; ok && state == modelsdevops.StatusSuccessful {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
copyProject := project.DeepCopy()
|
copyProject := project.DeepCopy()
|
||||||
// DeletionTimestamp.IsZero() means DevOps project has not been deleted.
|
// DeletionTimestamp.IsZero() means DevOps project has not been deleted.
|
||||||
if project.ObjectMeta.DeletionTimestamp.IsZero() {
|
if project.ObjectMeta.DeletionTimestamp.IsZero() {
|
||||||
|
//If the sync is successful, return handle
|
||||||
|
if state, ok := project.Annotations[devopsv1alpha3.DevOpeProjectSyncStatusAnnoKey]; ok && state == modelsdevops.StatusSuccessful {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Use Finalizers to sync DevOps status when DevOps project was deleted
|
// Use Finalizers to sync DevOps status when DevOps project was deleted
|
||||||
// https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#finalizers
|
// https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#finalizers
|
||||||
if !sliceutil.HasString(project.ObjectMeta.Finalizers, devopsv1alpha3.DevOpsProjectFinalizerName) {
|
if !sliceutil.HasString(project.ObjectMeta.Finalizers, devopsv1alpha3.DevOpsProjectFinalizerName) {
|
||||||
@@ -339,13 +342,31 @@ func (c *Controller) syncHandler(key string) error {
|
|||||||
} else {
|
} else {
|
||||||
// Finalizers processing logic
|
// Finalizers processing logic
|
||||||
if sliceutil.HasString(project.ObjectMeta.Finalizers, devopsv1alpha3.DevOpsProjectFinalizerName) {
|
if sliceutil.HasString(project.ObjectMeta.Finalizers, devopsv1alpha3.DevOpsProjectFinalizerName) {
|
||||||
|
delSuccess := false
|
||||||
if err := c.deleteDevOpsProjectInDevOps(project); err != nil {
|
if err := c.deleteDevOpsProjectInDevOps(project); err != nil {
|
||||||
|
// the status code should be 404 if the job does not exists
|
||||||
|
if srvErr, ok := err.(restful.ServiceError); ok {
|
||||||
|
delSuccess = srvErr.Code == http.StatusNotFound
|
||||||
|
} else if srvErr, ok := err.(*devopsClient.ErrorResponse); ok {
|
||||||
|
delSuccess = srvErr.Response.StatusCode == http.StatusNotFound
|
||||||
|
} else {
|
||||||
|
klog.Error(fmt.Sprintf("unexpected error type: %v, should be *restful.ServiceError", err))
|
||||||
|
}
|
||||||
|
|
||||||
klog.V(8).Info(err, fmt.Sprintf("failed to delete resource %s in devops", key))
|
klog.V(8).Info(err, fmt.Sprintf("failed to delete resource %s in devops", key))
|
||||||
return err
|
} else {
|
||||||
|
delSuccess = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if delSuccess {
|
||||||
|
project.ObjectMeta.Finalizers = sliceutil.RemoveString(project.ObjectMeta.Finalizers, func(item string) bool {
|
||||||
|
return item == devopsv1alpha3.DevOpsProjectFinalizerName
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// make sure the corresponding Jenkins job can be clean
|
||||||
|
// You can remove the finalizer via kubectl manually in a very special case that Jenkins might be not able to available anymore
|
||||||
|
return fmt.Errorf("failed to remove devopsproject finalizer due to bad communication with Jenkins")
|
||||||
}
|
}
|
||||||
project.ObjectMeta.Finalizers = sliceutil.RemoveString(project.ObjectMeta.Finalizers, func(item string) bool {
|
|
||||||
return item == devopsv1alpha3.DevOpsProjectFinalizerName
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err = c.kubesphereClient.DevopsV1alpha3().DevOpsProjects().Update(project)
|
_, err = c.kubesphereClient.DevopsV1alpha3().DevOpsProjects().Update(project)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -390,14 +411,9 @@ func (c *Controller) bindWorkspace(project *devopsv1alpha3.DevOpsProject) (*devo
|
|||||||
return project, nil
|
return project, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) deleteDevOpsProjectInDevOps(project *devopsv1alpha3.DevOpsProject) error {
|
func (c *Controller) deleteDevOpsProjectInDevOps(project *devopsv1alpha3.DevOpsProject) (err error) {
|
||||||
|
err = c.devopsClient.DeleteDevOpsProject(project.Status.AdminNamespace)
|
||||||
err := c.devopsClient.DeleteDevOpsProject(project.Status.AdminNamespace)
|
return
|
||||||
if err != nil {
|
|
||||||
klog.Errorf("error happened while deleting %s, %v", project.Name, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) generateNewNamespace(project *devopsv1alpha3.DevOpsProject) *v1.Namespace {
|
func (c *Controller) generateNewNamespace(project *devopsv1alpha3.DevOpsProject) *v1.Namespace {
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
"kubesphere.io/kubesphere/pkg/simple/client/devops"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DevOpsProjectRoleResponse struct {
|
type DevOpsProjectRoleResponse struct {
|
||||||
@@ -37,14 +36,12 @@ func (j *Jenkins) CreateDevOpsProject(projectId string) (string, error) {
|
|||||||
return projectId, nil
|
return projectId, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jenkins) DeleteDevOpsProject(projectId string) error {
|
func (j *Jenkins) DeleteDevOpsProject(projectId string) (err error) {
|
||||||
_, err := j.DeleteJob(projectId)
|
_, err = j.DeleteJob(projectId)
|
||||||
|
if err != nil {
|
||||||
if err != nil && devops.GetDevOpsStatusCode(err) != http.StatusNotFound {
|
|
||||||
klog.Errorf("%+v", err)
|
|
||||||
return restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
|
return restful.NewError(devops.GetDevOpsStatusCode(err), err.Error())
|
||||||
}
|
}
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Jenkins) GetDevOpsProject(projectId string) (string, error) {
|
func (j *Jenkins) GetDevOpsProject(projectId string) (string, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user