diff --git a/api/go.sum b/api/go.sum index 9be150c1c..7d2266b88 100644 --- a/api/go.sum +++ b/api/go.sum @@ -198,8 +198,9 @@ github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN github.com/aws/aws-sdk-go v1.28.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.29.11/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= github.com/aws/aws-sdk-go v1.29.32/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= -github.com/aws/aws-sdk-go v1.29.34 h1:yrzwfDaZFe9oT4AmQeNNunSQA7c0m2chz0B43+bJ1ok= github.com/aws/aws-sdk-go v1.29.34/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go v1.43.44 h1:t+97cY4ScE/czlNlK5iikUGi7w1fC0uop1OUalDIRT4= +github.com/aws/aws-sdk-go v1.43.44/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-xray-sdk-go v1.0.0-rc.5/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04= github.com/bazelbuild/bazel-gazelle v0.0.0-20181012220611-c728ce9f663e/go.mod h1:uHBSeeATKpVazAACZBDPL/Nk/UhQDDsJWDlqYJo8/Us= github.com/bazelbuild/buildtools v0.0.0-20180226164855-80c7f0d45d7e/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= @@ -860,8 +861,11 @@ github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/ github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= @@ -1580,6 +1584,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180603041954-1e0a3fa8ba9a/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1691,10 +1697,13 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/api/turing/api/deployment_controller.go b/api/turing/api/deployment_controller.go index 5ba6fc918..01b2118c2 100644 --- a/api/turing/api/deployment_controller.go +++ b/api/turing/api/deployment_controller.go @@ -72,7 +72,7 @@ func (c RouterDeploymentController) deployOrRollbackRouter( // Save the error from the failed deployment errorStrings = append(errorStrings, err.Error()) // Remove cluster resources from the failed deployment attempt - err = c.DeploymentService.UndeployRouterVersion(project, environment, routerVersion, eventsCh) + err = c.DeploymentService.UndeployRouterVersion(project, environment, routerVersion, eventsCh, true) if err != nil { errorStrings = append(errorStrings, err.Error()) eventsCh.Write(models.NewErrorEvent( @@ -102,7 +102,7 @@ func (c RouterDeploymentController) deployOrRollbackRouter( if err != nil { errorStrings = append(errorStrings, err.Error()) } else { - err = c.DeploymentService.UndeployRouterVersion(project, environment, currVersion, eventsCh) + err = c.DeploymentService.UndeployRouterVersion(project, environment, currVersion, eventsCh, false) if err != nil { errorStrings = append(errorStrings, err.Error()) } @@ -313,7 +313,12 @@ func (c RouterDeploymentController) undeployRouter( if routerVersion.Status == models.RouterVersionStatusPending || routerVersion.Status == models.RouterVersionStatusDeployed { // Remove cluster resources - err = c.DeploymentService.UndeployRouterVersion(project, environment, routerVersion, eventsCh) + if routerVersion.Status == models.RouterVersionStatusPending { + err = c.DeploymentService.UndeployRouterVersion(project, environment, routerVersion, eventsCh, true) + } else if routerVersion.Status == models.RouterVersionStatusDeployed { + err = c.DeploymentService.UndeployRouterVersion(project, environment, routerVersion, eventsCh, false) + } + if err != nil { errorStrings = append(errorStrings, err.Error()) } diff --git a/api/turing/api/deployment_controller_test.go b/api/turing/api/deployment_controller_test.go index f2c0339f0..947eee10a 100644 --- a/api/turing/api/deployment_controller_test.go +++ b/api/turing/api/deployment_controller_test.go @@ -270,7 +270,7 @@ func TestRollbackVersionSuccess(t *testing.T) { ds := &mocks.DeploymentService{} ds.On("DeployRouterVersion", project, environment, newVer, testSvcAcct, "", "", mock.Anything, json.RawMessage(nil), mock.Anything).Return("", errors.New("error")) - ds.On("UndeployRouterVersion", project, environment, newVer, mock.Anything). + ds.On("UndeployRouterVersion", project, environment, newVer, mock.Anything, true). Return(nil) es := &mocks.EventService{} @@ -301,7 +301,7 @@ func TestRollbackVersionSuccess(t *testing.T) { // is correct, and the endpoint value remains unchanged. Also test that the statuses - // the new vers's deployment status should be failed and the router and the current // ver should be deployed. - ds.AssertCalled(t, "UndeployRouterVersion", project, environment, newVer, mock.Anything) + ds.AssertCalled(t, "UndeployRouterVersion", project, environment, newVer, mock.Anything, true) assert.Equal(t, models.ID(200), router.CurrRouterVersion.ID) assert.Equal(t, "current-endpoint", router.Endpoint) assert.Equal(t, models.RouterVersionStatusDeployed, router.CurrRouterVersion.Status) @@ -370,8 +370,8 @@ func TestUndeployRouterSuccess(t *testing.T) { Return([]*models.RouterVersion{routerVersion, pendingRouterVersion}, nil) ds := &mocks.DeploymentService{} - ds.On("UndeployRouterVersion", project, environment, routerVersion, mock.Anything).Return(nil) - ds.On("UndeployRouterVersion", project, environment, pendingRouterVersion, mock.Anything).Return(nil) + ds.On("UndeployRouterVersion", project, environment, routerVersion, mock.Anything, false).Return(nil) + ds.On("UndeployRouterVersion", project, environment, pendingRouterVersion, mock.Anything, true).Return(nil) ds.On("DeleteRouterEndpoint", project, environment, &models.RouterVersion{Router: router}).Return(nil) es := &mocks.EventService{} @@ -400,8 +400,8 @@ func TestUndeployRouterSuccess(t *testing.T) { assert.Equal(t, models.RouterVersionStatusUndeployed, router.CurrRouterVersion.Status) assert.Equal(t, "", router.Endpoint) // Assert calls - ds.AssertCalled(t, "UndeployRouterVersion", project, environment, routerVersion, mock.Anything) - ds.AssertCalled(t, "UndeployRouterVersion", project, environment, pendingRouterVersion, mock.Anything) + ds.AssertCalled(t, "UndeployRouterVersion", project, environment, routerVersion, mock.Anything, false) + ds.AssertCalled(t, "UndeployRouterVersion", project, environment, pendingRouterVersion, mock.Anything, true) ds.AssertCalled(t, "DeleteRouterEndpoint", project, environment, &models.RouterVersion{Router: router}) rs.AssertCalled(t, "Save", modifiedRouter) } diff --git a/api/turing/batch/ensembling/controller.go b/api/turing/batch/ensembling/controller.go index 15a794f23..caf955d00 100644 --- a/api/turing/batch/ensembling/controller.go +++ b/api/turing/batch/ensembling/controller.go @@ -252,12 +252,12 @@ func (c *ensemblingController) createSecret(request *CreateEnsemblingJobRequest, } func (c *ensemblingController) cleanup(jobName string, namespace string) { - err := c.clusterController.DeleteSecret(jobName, namespace) + err := c.clusterController.DeleteSecret(jobName, namespace, false) if err != nil { log.Warnf("failed deleting secret %s in namespace %s: %v", jobName, namespace, err) } - err = c.clusterController.DeleteConfigMap(jobName, namespace) + err = c.clusterController.DeleteConfigMap(jobName, namespace, false) if err != nil { log.Warnf("failed deleting job spec %s in namespace %s: %v", jobName, namespace, err) } diff --git a/api/turing/batch/ensembling/controller_test.go b/api/turing/batch/ensembling/controller_test.go index e789a8500..8b7ca0016 100644 --- a/api/turing/batch/ensembling/controller_test.go +++ b/api/turing/batch/ensembling/controller_test.go @@ -219,8 +219,8 @@ func TestCreate(t *testing.T) { clusterController: func() cluster.Controller { ctrler := &clustermock.Controller{} ctrler.On("CreateNamespace", mock.Anything).Return(fmt.Errorf("hi")) - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) return ctrler }, mlpService: func() service.MLPService { @@ -251,8 +251,8 @@ func TestCreate(t *testing.T) { nil, fmt.Errorf("hi"), ) - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) return ctrler }, mlpService: func() service.MLPService { @@ -291,8 +291,8 @@ func TestCreate(t *testing.T) { nil, fmt.Errorf("hi"), ) - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) return ctrler }, mlpService: func() service.MLPService { @@ -342,8 +342,8 @@ func TestCreate(t *testing.T) { mock.Anything, mock.Anything, ).Return(nil, fmt.Errorf("hi")) - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) return ctrler }, mlpService: func() service.MLPService { @@ -394,8 +394,8 @@ func TestCreate(t *testing.T) { mock.Anything, mock.Anything, ).Return(nil, nil) - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) return ctrler }, mlpService: func() service.MLPService { @@ -448,8 +448,8 @@ func TestCreate(t *testing.T) { ).Return(nil, nil) ctrler.On("CreateSecret", mock.Anything, mock.Anything).Return(nil, nil) ctrler.On("ApplyConfigMap", mock.Anything, mock.Anything).Return(fmt.Errorf("hi")) - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) return ctrler }, mlpService: func() service.MLPService { @@ -504,8 +504,8 @@ func TestCreate(t *testing.T) { ctrler.On("CreateSecret", mock.Anything, mock.Anything).Return(nil, nil) ctrler.On("ApplyConfigMap", mock.Anything, mock.Anything).Return(nil) ctrler.On("CreateSparkApplication", mock.Anything, mock.Anything).Return(nil, fmt.Errorf("hi")) - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) return ctrler }, mlpService: func() service.MLPService { @@ -661,8 +661,8 @@ func TestDelete(t *testing.T) { "success | delete spark application": { clusterController: func() cluster.Controller { ctrler := &clustermock.Controller{} - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) ctrler.On("GetSparkApplication", mock.Anything, mock.Anything).Return( &apisparkv1beta2.SparkApplication{}, @@ -678,8 +678,8 @@ func TestDelete(t *testing.T) { "success | no such job": { clusterController: func() cluster.Controller { ctrler := &clustermock.Controller{} - ctrler.On("DeleteSecret", mock.Anything, mock.Anything).Return(nil) - ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) + ctrler.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + ctrler.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) ctrler.On("GetSparkApplication", mock.Anything, mock.Anything).Return( nil, diff --git a/api/turing/cluster/controller.go b/api/turing/cluster/controller.go index 65d89506e..256540ede 100644 --- a/api/turing/cluster/controller.go +++ b/api/turing/cluster/controller.go @@ -64,19 +64,20 @@ type clusterConfig struct { // Controller defines the operations supported by the cluster controller type Controller interface { DeployKnativeService(ctx context.Context, svc *KnativeService) error - DeleteKnativeService(svcName string, namespace string, timeout time.Duration) error + DeleteKnativeService(svcName string, namespace string, timeout time.Duration, ignoreNotFound bool) error GetKnativeServiceURL(svcName string, namespace string) string ApplyIstioVirtualService(ctx context.Context, routerEndpoint *VirtualService) error DeleteIstioVirtualService(svcName string, namespace string, timeout time.Duration) error DeployKubernetesService(ctx context.Context, svc *KubernetesService) error - DeleteKubernetesService(svcName string, namespace string, timeout time.Duration) error + DeleteKubernetesDeployment(name string, namespace string, timeout time.Duration, ignoreNotFound bool) error + DeleteKubernetesService(svcName string, namespace string, timeout time.Duration, ignoreNotFound bool) error CreateNamespace(name string) error ApplyConfigMap(namespace string, configMap *ConfigMap) error - DeleteConfigMap(name, namespace string) error + DeleteConfigMap(name string, namespace string, ignoreNotFound bool) error CreateSecret(ctx context.Context, secret *Secret) error - DeleteSecret(secretName string, namespace string) error + DeleteSecret(secretName string, namespace string, ignoreNotFound bool) error ApplyPersistentVolumeClaim(ctx context.Context, namespace string, pvc *PersistentVolumeClaim) error - DeletePersistentVolumeClaim(pvcName string, namespace string) error + DeletePersistentVolumeClaim(pvcName string, namespace string, ignoreNotFound bool) error ListPods(namespace string, labelSelector string) (*apicorev1.PodList, error) ListPodLogs(namespace string, podName string, opts *apicorev1.PodLogOptions) (io.ReadCloser, error) CreateJob(namespace string, job Job) (*apibatchv1.Job, error) @@ -235,9 +236,12 @@ func (c *controller) ApplyConfigMap(namespace string, configMap *ConfigMap) erro } // DeleteConfigMap deletes a configmap if exists. -func (c *controller) DeleteConfigMap(name, namespace string) error { +func (c *controller) DeleteConfigMap(name string, namespace string, ignoreNotFound bool) error { _, err := c.k8sCoreClient.ConfigMaps(namespace).Get(name, metav1.GetOptions{}) if err != nil { + if ignoreNotFound { + return nil + } return err } return c.k8sCoreClient.ConfigMaps(namespace).Delete(name, &metav1.DeleteOptions{}) @@ -294,6 +298,7 @@ func (c *controller) DeleteKnativeService( svcName string, namespace string, timeout time.Duration, + ignoreNotFound bool, ) error { // Init knative ServicesGetter services := c.knServingClient.Services(namespace) @@ -301,6 +306,9 @@ func (c *controller) DeleteKnativeService( // Get the service _, err := services.Get(svcName, metav1.GetOptions{}) if err != nil { + if ignoreNotFound { + return nil + } return err } @@ -375,26 +383,47 @@ func (c *controller) DeployKubernetesService( return c.waitDeploymentReady(ctx, svcConf.Name, svcConf.Namespace) } -// DeleteKubernetesService deletes a kubernetes service an deployment -func (c *controller) DeleteKubernetesService(svcName string, namespace string, timeout time.Duration) error { +// DeleteKubernetesDeployment deletes a kubernetes deployment +func (c *controller) DeleteKubernetesDeployment( + name string, + namespace string, + timeout time.Duration, + ignoreNotFound bool, +) error { gracePeriod := int64(timeout.Seconds()) delOptions := &metav1.DeleteOptions{ GracePeriodSeconds: &gracePeriod, } deployments := c.k8sAppsClient.Deployments(namespace) - _, err := deployments.Get(svcName, metav1.GetOptions{}) + _, err := deployments.Get(name, metav1.GetOptions{}) if err != nil { + if ignoreNotFound { + return nil + } return err } - err = deployments.Delete(svcName, delOptions) - if err != nil { - return err + return deployments.Delete(name, delOptions) +} + +// DeleteKubernetesService deletes a kubernetes service +func (c *controller) DeleteKubernetesService( + svcName string, + namespace string, + timeout time.Duration, + ignoreNotFound bool, +) error { + gracePeriod := int64(timeout.Seconds()) + delOptions := &metav1.DeleteOptions{ + GracePeriodSeconds: &gracePeriod, } services := c.k8sCoreClient.Services(namespace) - _, err = services.Get(svcName, metav1.GetOptions{}) + _, err := services.Get(svcName, metav1.GetOptions{}) if err != nil { + if ignoreNotFound { + return nil + } return err } return services.Delete(svcName, delOptions) @@ -442,10 +471,13 @@ func (c *controller) CreateSecret(ctx context.Context, secret *Secret) error { } // DeleteSecret deletes a secret -func (c *controller) DeleteSecret(secretName string, namespace string) error { +func (c *controller) DeleteSecret(secretName string, namespace string, ignoreNotFound bool) error { secrets := c.k8sCoreClient.Secrets(namespace) _, err := secrets.Get(secretName, metav1.GetOptions{}) if err != nil { + if ignoreNotFound { + return nil + } return fmt.Errorf("unable to get secret with name %s: %s", secretName, err.Error()) } return secrets.Delete(secretName, &metav1.DeleteOptions{}) @@ -493,10 +525,13 @@ func (c *controller) ApplyPersistentVolumeClaim( } // DeletePersistentVolumeClaim deletes the PVC in the given namespace. -func (c *controller) DeletePersistentVolumeClaim(pvcName string, namespace string) error { +func (c *controller) DeletePersistentVolumeClaim(pvcName string, namespace string, ignoreNotFound bool) error { pvcs := c.k8sCoreClient.PersistentVolumeClaims(namespace) _, err := pvcs.Get(pvcName, metav1.GetOptions{}) if err != nil { + if ignoreNotFound { + return nil + } return fmt.Errorf("unable to get pvc with name %s: %s", pvcName, err.Error()) } return pvcs.Delete(pvcName, &metav1.DeleteOptions{}) diff --git a/api/turing/cluster/controller_test.go b/api/turing/cluster/controller_test.go index a6883e17e..c79a5b5e5 100644 --- a/api/turing/cluster/controller_test.go +++ b/api/turing/cluster/controller_test.go @@ -387,101 +387,269 @@ func TestDeleteKnativeService(t *testing.T) { Version: knativeVersion, Resource: knativeResource, } + cs := knservingclientset.NewSimpleClientset() - // Define reactors. The reactors also validate that they are called - // with the expected parameters. - reactors := []reactor{ + tests := []struct { + name string + reactors []reactor + ignoreNotFound bool + hasErr bool + }{ { - verb: reactorVerbs.Get, - resource: knativeResource, - rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { - expAction := k8stesting.NewGetAction(resourceItem, testNamespace, testName) - // Check that the method is called with the expected action - assert.Equal(t, expAction, action) - // Nil error indicates Get success to the DeleteKnativeService() method - return true, nil, nil + "not_exists; ignore knative resource not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: knativeResource, + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(resourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + // Return nil object and error to indicate non existent object + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, testName) + }, + }, }, + true, + false, }, { - verb: reactorVerbs.Delete, - resource: knativeResource, - rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { - expAction := k8stesting.NewDeleteAction(resourceItem, testNamespace, testName) - // Check that the method is called with the expected action - assert.Equal(t, expAction, action) - // Nil error indicates Delete success - return true, nil, nil + "exists; ignore knative resource not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: knativeResource, + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(resourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, + { + verb: reactorVerbs.Delete, + resource: knativeResource, + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewDeleteAction(resourceItem, testNamespace, testName) + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, }, + true, + false, + }, + { + "not_exists; do not ignore knative resource not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: knativeResource, + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(resourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + // Return nil object and error to indicate non existent object + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, testName) + }, + }, + }, + false, + true, }, } - // Create test controller - c := createTestKnController(knservingclientset.NewSimpleClientset(), reactors) - // Run tests - err := c.DeleteKnativeService(testName, testNamespace, time.Second*5) - // Validate no error - assert.NoError(t, err) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Create test controller + c := createTestKnController(cs, tc.reactors) + // Run test + err := c.DeleteKnativeService(testName, testNamespace, time.Second*5, tc.ignoreNotFound) + // Validate no error + assert.Equal(t, err != nil, tc.hasErr) + }) + } } -func TestDeleteK8sService(t *testing.T) { +func TestDeleteKubernetesDeployment(t *testing.T) { testName, testNamespace := "test-name", "test-namespace" deploymentResourceItem := schema.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "deployments", } + cs := fake.NewSimpleClientset() + + tests := []struct { + name string + reactors []reactor + ignoreNotFound bool + hasErr bool + }{ + { + "not_exists; ignore deployment not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: "deployments", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(deploymentResourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + // Return nil object and error to indicate non existent object + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, testName) + }, + }, + }, + true, + false, + }, + { + "exists; ignore deployment not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: "deployments", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(deploymentResourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, + { + verb: reactorVerbs.Delete, + resource: "deployments", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewDeleteAction(deploymentResourceItem, testNamespace, testName) + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, + }, + true, + false, + }, + { + "not_exists; do not ignore deployment not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: "deployments", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(deploymentResourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + // Return nil object and error to indicate non existent object + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, testName) + }, + }, + }, + false, + true, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Create test controller + c := createTestK8sController(cs, tc.reactors) + // Run test + err := c.DeleteKubernetesDeployment(testName, testNamespace, time.Second*5, tc.ignoreNotFound) + // Validate no error + assert.Equal(t, err != nil, tc.hasErr) + }) + } +} + +func TestDeleteKubernetesService(t *testing.T) { + testName, testNamespace := "test-name", "test-namespace" svcResourceItem := schema.GroupVersionResource{ Version: "v1", Resource: "services", } + cs := fake.NewSimpleClientset() - // Define reactors. The reactors also validate that they are called - // with the expected parameters. - reactors := []reactor{ - { - verb: reactorVerbs.Get, - resource: "deployments", - rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { - expAction := k8stesting.NewGetAction(deploymentResourceItem, testNamespace, testName) - assert.Equal(t, expAction, action) - return true, nil, nil - }, - }, + tests := []struct { + name string + reactors []reactor + ignoreNotFound bool + hasErr bool + }{ { - verb: reactorVerbs.Delete, - resource: "deployments", - rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { - expAction := k8stesting.NewDeleteAction(deploymentResourceItem, testNamespace, testName) - assert.Equal(t, expAction, action) - return true, nil, nil + "not_exists; ignore service not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: "services", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(svcResourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + // Return nil object and error to indicate non existent object + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, testName) + }, + }, }, + true, + false, }, { - verb: reactorVerbs.Get, - resource: "services", - rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { - expAction := k8stesting.NewGetAction(svcResourceItem, testNamespace, testName) - assert.Equal(t, expAction, action) - return true, nil, nil + "exists; ignore service not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: "services", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(svcResourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, + { + verb: reactorVerbs.Delete, + resource: "services", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewDeleteAction(svcResourceItem, testNamespace, testName) + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, }, + true, + false, }, { - verb: reactorVerbs.Delete, - resource: "services", - rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { - expAction := k8stesting.NewDeleteAction(svcResourceItem, testNamespace, testName) - assert.Equal(t, expAction, action) - return true, nil, nil + "not_exists; do not ignore service not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: "services", + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(svcResourceItem, testNamespace, testName) + // Check that the method is called with the expected action + assert.Equal(t, expAction, action) + // Return nil object and error to indicate non existent object + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, testName) + }, + }, }, + false, + true, }, } - // Create test controller - c := createTestK8sController(fake.NewSimpleClientset(), reactors) - // Run tests - err := c.DeleteKubernetesService(testName, testNamespace, time.Second*5) - // Validate no error - assert.NoError(t, err) + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + // Create test controller + c := createTestK8sController(cs, tc.reactors) + // Run test + err := c.DeleteKubernetesService(testName, testNamespace, time.Second*5, tc.ignoreNotFound) + // Validate no error + assert.Equal(t, err != nil, tc.hasErr) + }) + } } func TestCreateKanikoJob(t *testing.T) { @@ -1182,12 +1350,15 @@ func TestDeleteSecret(t *testing.T) { secretName := "secret" cs := fake.NewSimpleClientset() + tests := []struct { - name string - reactors []reactor - hasErr bool + name string + reactors []reactor + ignoreNotFound bool + hasErr bool }{ - {"not_exists", + { + "not_exists; ignore secret not found", []reactor{ { verb: reactorVerbs.Get, @@ -1202,9 +1373,10 @@ func TestDeleteSecret(t *testing.T) { }, }, true, + false, }, { - "delete_secret", + "exists; ignore secret not found", []reactor{ { verb: reactorVerbs.Get, @@ -1221,14 +1393,31 @@ func TestDeleteSecret(t *testing.T) { resource: secretResource.Resource, rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { expAction := k8stesting.NewDeleteAction(secretResource, testNamespace, secretName) + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, + }, + true, + false, + }, + { + "not_exists; do not ignore secret not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: secretResource.Resource, + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(secretResource, testNamespace, secretName) // Check that the method is called with the expected action assert.Equal(t, expAction, action) // Return nil object and error to indicate non existent object - return true, nil, nil + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, secretName) }, }, }, false, + true, }, } @@ -1237,7 +1426,7 @@ func TestDeleteSecret(t *testing.T) { // Create test controller c := createTestK8sController(cs, tc.reactors) // Run test - err := c.DeleteSecret(secretName, testNamespace) + err := c.DeleteSecret(secretName, testNamespace, tc.ignoreNotFound) // Validate no error assert.Equal(t, err != nil, tc.hasErr) }) @@ -1353,12 +1542,15 @@ func TestDeletePVC(t *testing.T) { Size: volSize, } cs := fake.NewSimpleClientset() + tests := []struct { - name string - reactors []reactor - hasErr bool + name string + reactors []reactor + ignoreNotFound bool + hasErr bool }{ - {"not_exists", + { + "not_exists; ignore pvc not found", []reactor{ { verb: reactorVerbs.Get, @@ -1373,9 +1565,10 @@ func TestDeletePVC(t *testing.T) { }, }, true, + false, }, { - "delete_pvc", + "exists; ignore pvc not found", []reactor{ { verb: reactorVerbs.Get, @@ -1392,14 +1585,31 @@ func TestDeletePVC(t *testing.T) { resource: pvcResource.Resource, rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { expAction := k8stesting.NewDeleteAction(pvcResource, testNamespace, pvcConf.Name) + assert.Equal(t, expAction, action) + return true, nil, nil + }, + }, + }, + true, + false, + }, + { + "not_exists; do not ignore pvc not found", + []reactor{ + { + verb: reactorVerbs.Get, + resource: pvcResource.Resource, + rFunc: func(action k8stesting.Action) (bool, runtime.Object, error) { + expAction := k8stesting.NewGetAction(pvcResource, testNamespace, pvcConf.Name) // Check that the method is called with the expected action assert.Equal(t, expAction, action) // Return nil object and error to indicate non existent object - return true, nil, nil + return true, nil, k8serrors.NewNotFound(schema.GroupResource{}, pvcConf.Name) }, }, }, false, + true, }, } @@ -1408,7 +1618,7 @@ func TestDeletePVC(t *testing.T) { // Create test controller c := createTestK8sController(cs, tc.reactors) // Run test - err := c.DeletePersistentVolumeClaim(pvcConf.Name, testNamespace) + err := c.DeletePersistentVolumeClaim(pvcConf.Name, testNamespace, tc.ignoreNotFound) // Validate no error assert.Equal(t, tc.hasErr, err != nil) }) diff --git a/api/turing/cluster/mocks/controller.go b/api/turing/cluster/mocks/controller.go index cee5438dc..af98ee352 100644 --- a/api/turing/cluster/mocks/controller.go +++ b/api/turing/cluster/mocks/controller.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.6.0. DO NOT EDIT. +// Code generated by mockery v2.10.4. DO NOT EDIT. package mocks @@ -212,13 +212,13 @@ func (_m *Controller) CreateSparkApplication(namespace string, request *cluster. return r0, r1 } -// DeleteConfigMap provides a mock function with given fields: name, namespace -func (_m *Controller) DeleteConfigMap(name string, namespace string) error { - ret := _m.Called(name, namespace) +// DeleteConfigMap provides a mock function with given fields: name, namespace, ignoreNotFound +func (_m *Controller) DeleteConfigMap(name string, namespace string, ignoreNotFound bool) error { + ret := _m.Called(name, namespace, ignoreNotFound) var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(name, namespace) + if rf, ok := ret.Get(0).(func(string, string, bool) error); ok { + r0 = rf(name, namespace, ignoreNotFound) } else { r0 = ret.Error(0) } @@ -254,13 +254,13 @@ func (_m *Controller) DeleteJob(namespace string, jobName string) error { return r0 } -// DeleteKnativeService provides a mock function with given fields: svcName, namespace, timeout -func (_m *Controller) DeleteKnativeService(svcName string, namespace string, timeout time.Duration) error { - ret := _m.Called(svcName, namespace, timeout) +// DeleteKnativeService provides a mock function with given fields: svcName, namespace, timeout, ignoreNotFound +func (_m *Controller) DeleteKnativeService(svcName string, namespace string, timeout time.Duration, ignoreNotFound bool) error { + ret := _m.Called(svcName, namespace, timeout, ignoreNotFound) var r0 error - if rf, ok := ret.Get(0).(func(string, string, time.Duration) error); ok { - r0 = rf(svcName, namespace, timeout) + if rf, ok := ret.Get(0).(func(string, string, time.Duration, bool) error); ok { + r0 = rf(svcName, namespace, timeout, ignoreNotFound) } else { r0 = ret.Error(0) } @@ -268,13 +268,13 @@ func (_m *Controller) DeleteKnativeService(svcName string, namespace string, tim return r0 } -// DeleteKubernetesService provides a mock function with given fields: svcName, namespace, timeout -func (_m *Controller) DeleteKubernetesService(svcName string, namespace string, timeout time.Duration) error { - ret := _m.Called(svcName, namespace, timeout) +// DeleteKubernetesDeployment provides a mock function with given fields: name, namespace, timeout, ignoreNotFound +func (_m *Controller) DeleteKubernetesDeployment(name string, namespace string, timeout time.Duration, ignoreNotFound bool) error { + ret := _m.Called(name, namespace, timeout, ignoreNotFound) var r0 error - if rf, ok := ret.Get(0).(func(string, string, time.Duration) error); ok { - r0 = rf(svcName, namespace, timeout) + if rf, ok := ret.Get(0).(func(string, string, time.Duration, bool) error); ok { + r0 = rf(name, namespace, timeout, ignoreNotFound) } else { r0 = ret.Error(0) } @@ -282,13 +282,13 @@ func (_m *Controller) DeleteKubernetesService(svcName string, namespace string, return r0 } -// DeletePersistentVolumeClaim provides a mock function with given fields: pvcName, namespace -func (_m *Controller) DeletePersistentVolumeClaim(pvcName string, namespace string) error { - ret := _m.Called(pvcName, namespace) +// DeleteKubernetesService provides a mock function with given fields: svcName, namespace, timeout, ignoreNotFound +func (_m *Controller) DeleteKubernetesService(svcName string, namespace string, timeout time.Duration, ignoreNotFound bool) error { + ret := _m.Called(svcName, namespace, timeout, ignoreNotFound) var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(pvcName, namespace) + if rf, ok := ret.Get(0).(func(string, string, time.Duration, bool) error); ok { + r0 = rf(svcName, namespace, timeout, ignoreNotFound) } else { r0 = ret.Error(0) } @@ -296,13 +296,27 @@ func (_m *Controller) DeletePersistentVolumeClaim(pvcName string, namespace stri return r0 } -// DeleteSecret provides a mock function with given fields: secretName, namespace -func (_m *Controller) DeleteSecret(secretName string, namespace string) error { - ret := _m.Called(secretName, namespace) +// DeletePersistentVolumeClaim provides a mock function with given fields: pvcName, namespace, ignoreNotFound +func (_m *Controller) DeletePersistentVolumeClaim(pvcName string, namespace string, ignoreNotFound bool) error { + ret := _m.Called(pvcName, namespace, ignoreNotFound) var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(secretName, namespace) + if rf, ok := ret.Get(0).(func(string, string, bool) error); ok { + r0 = rf(pvcName, namespace, ignoreNotFound) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// DeleteSecret provides a mock function with given fields: secretName, namespace, ignoreNotFound +func (_m *Controller) DeleteSecret(secretName string, namespace string, ignoreNotFound bool) error { + ret := _m.Called(secretName, namespace, ignoreNotFound) + + var r0 error + if rf, ok := ret.Get(0).(func(string, string, bool) error); ok { + r0 = rf(secretName, namespace, ignoreNotFound) } else { r0 = ret.Error(0) } diff --git a/api/turing/service/mocks/router_deployment_service.go b/api/turing/service/mocks/router_deployment_service.go index 89b105fba..04f1fc1c0 100644 --- a/api/turing/service/mocks/router_deployment_service.go +++ b/api/turing/service/mocks/router_deployment_service.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.10.0. DO NOT EDIT. +// Code generated by mockery v2.10.4. DO NOT EDIT. package mocks @@ -56,13 +56,13 @@ func (_m *DeploymentService) DeployRouterVersion(project *client.Project, enviro return r0, r1 } -// UndeployRouterVersion provides a mock function with given fields: project, environment, routerVersion, eventsCh -func (_m *DeploymentService) UndeployRouterVersion(project *client.Project, environment *merlinclient.Environment, routerVersion *models.RouterVersion, eventsCh *service.EventChannel) error { - ret := _m.Called(project, environment, routerVersion, eventsCh) +// UndeployRouterVersion provides a mock function with given fields: project, environment, routerVersion, eventsCh, isCleanUp +func (_m *DeploymentService) UndeployRouterVersion(project *client.Project, environment *merlinclient.Environment, routerVersion *models.RouterVersion, eventsCh *service.EventChannel, isCleanUp bool) error { + ret := _m.Called(project, environment, routerVersion, eventsCh, isCleanUp) var r0 error - if rf, ok := ret.Get(0).(func(*client.Project, *merlinclient.Environment, *models.RouterVersion, *service.EventChannel) error); ok { - r0 = rf(project, environment, routerVersion, eventsCh) + if rf, ok := ret.Get(0).(func(*client.Project, *merlinclient.Environment, *models.RouterVersion, *service.EventChannel, bool) error); ok { + r0 = rf(project, environment, routerVersion, eventsCh, isCleanUp) } else { r0 = ret.Error(0) } diff --git a/api/turing/service/router_deployment_service.go b/api/turing/service/router_deployment_service.go index 799bab870..eb72a1c02 100644 --- a/api/turing/service/router_deployment_service.go +++ b/api/turing/service/router_deployment_service.go @@ -38,6 +38,7 @@ type DeploymentService interface { environment *merlin.Environment, routerVersion *models.RouterVersion, eventsCh *EventChannel, + isCleanUp bool, ) error DeleteRouterEndpoint(project *mlp.Project, environment *merlin.Environment, @@ -231,6 +232,7 @@ func (ds *deploymentService) UndeployRouterVersion( environment *merlin.Environment, routerVersion *models.RouterVersion, eventsCh *EventChannel, + isCleanUp bool, ) error { ctx, cancel := context.WithTimeout(context.Background(), ds.deploymentTimeout) defer cancel() @@ -243,7 +245,7 @@ func (ds *deploymentService) UndeployRouterVersion( // Delete secret eventsCh.Write(models.NewInfoEvent(models.EventStageDeletingDependencies, "deleting secrets")) secret := ds.svcBuilder.NewSecret(routerVersion, project, "", "", "") - err = deleteSecret(controller, secret) + err = deleteSecret(controller, secret, isCleanUp) if err != nil { return err } @@ -264,11 +266,11 @@ func (ds *deploymentService) UndeployRouterVersion( if routerVersion.LogConfig.ResultLoggerType == models.BigQueryLogger { fluentdService := ds.svcBuilder.NewFluentdService(routerVersion, project, "", ds.routerDefaults.FluentdConfig) - err = deleteK8sService(controller, fluentdService, ds.deploymentTimeout) + err = deleteK8sService(controller, fluentdService, ds.deploymentTimeout, isCleanUp) if err != nil { errs = append(errs, err.Error()) } - err = deletePVC(controller, project.Name, fluentdService.PersistentVolumeClaim) + err = deletePVC(controller, project.Name, fluentdService.PersistentVolumeClaim, isCleanUp) if err != nil { errs = append(errs, err.Error()) } @@ -284,7 +286,7 @@ func (ds *deploymentService) UndeployRouterVersion( // Delete experiment engine plugins server if routerVersion.ExperimentEngine.PluginConfig != nil { pluginsServerSvc := ds.svcBuilder.NewPluginsServerService(routerVersion, project) - err = deleteK8sService(controller, pluginsServerSvc, ds.deploymentTimeout) + err = deleteK8sService(controller, pluginsServerSvc, ds.deploymentTimeout, isCleanUp) if err != nil { eventsCh.Write( models.NewErrorEvent( @@ -297,7 +299,7 @@ func (ds *deploymentService) UndeployRouterVersion( } // Delete all components - err = deleteKnServices(ctx, controller, services, ds.deploymentDeletionTimeout, eventsCh) + err = deleteKnServices(ctx, controller, services, ds.deploymentDeletionTimeout, eventsCh, isCleanUp) if err != nil { errs = append(errs, err.Error()) } @@ -477,8 +479,22 @@ func deleteK8sService( controller cluster.Controller, service *cluster.KubernetesService, timeout time.Duration, + isCleanUp bool, ) error { - return controller.DeleteKubernetesService(service.Name, service.Namespace, timeout) + var err error + if isCleanUp { + err = controller.DeleteKubernetesDeployment(service.Name, service.Namespace, timeout, true) + } else { + err = controller.DeleteKubernetesDeployment(service.Name, service.Namespace, timeout, false) + } + if err != nil { + return err + } + + if isCleanUp { + return controller.DeleteKubernetesService(service.Name, service.Namespace, timeout, true) + } + return controller.DeleteKubernetesService(service.Name, service.Namespace, timeout, false) } // createSecret creates a secret. @@ -496,8 +512,11 @@ func createSecret( } // deleteSecret deletes a secret. -func deleteSecret(controller cluster.Controller, secret *cluster.Secret) error { - return controller.DeleteSecret(secret.Name, secret.Namespace) +func deleteSecret(controller cluster.Controller, secret *cluster.Secret, isCleanUp bool) error { + if isCleanUp { + return controller.DeleteSecret(secret.Name, secret.Namespace, true) + } + return controller.DeleteSecret(secret.Name, secret.Namespace, false) } func createPVC( @@ -518,8 +537,12 @@ func deletePVC( controller cluster.Controller, namespace string, pvc *cluster.PersistentVolumeClaim, + isCleanUp bool, ) error { - return controller.DeletePersistentVolumeClaim(pvc.Name, namespace) + if isCleanUp { + return controller.DeletePersistentVolumeClaim(pvc.Name, namespace, true) + } + return controller.DeletePersistentVolumeClaim(pvc.Name, namespace, false) } // deployKnServices deploys all services simulateneously and waits for all of them to @@ -580,6 +603,7 @@ func deleteKnServices( services []*cluster.KnativeService, timeout time.Duration, eventsCh *EventChannel, + isCleanUp bool, ) error { // Define delete function deleteFunc := func(_ context.Context, @@ -589,10 +613,15 @@ func deleteKnServices( eventsCh *EventChannel, ) { defer wg.Done() + var err error eventsCh.Write(models.NewInfoEvent( models.EventStageUndeployingServices, "deleting service %s", svc.Name)) if svc.ConfigMap != nil { - err := controller.DeleteConfigMap(svc.ConfigMap.Name, svc.Namespace) + if isCleanUp { + err = controller.DeleteConfigMap(svc.ConfigMap.Name, svc.Namespace, true) + } else { + err = controller.DeleteConfigMap(svc.ConfigMap.Name, svc.Namespace, false) + } if err != nil { err = errors.Wrapf(err, "Failed to delete config map %s", svc.ConfigMap.Name) eventsCh.Write(models.NewErrorEvent( @@ -600,7 +629,12 @@ func deleteKnServices( errCh <- err } } - err := controller.DeleteKnativeService(svc.Name, svc.Namespace, timeout) + + if isCleanUp { + err = controller.DeleteKnativeService(svc.Name, svc.Namespace, timeout, true) + } else { + err = controller.DeleteKnativeService(svc.Name, svc.Namespace, timeout, false) + } if err != nil { err = errors.Wrapf(err, "Error when deleting %s", svc.Name) eventsCh.Write(models.NewErrorEvent( @@ -615,7 +649,7 @@ func deleteKnServices( return updateKnServices(ctx, services, deleteFunc, eventsCh) } -// updateKnServices is a helper method for deployment / deletion of serivices that runs the +// updateKnServices is a helper method for deployment / deletion of services that runs the // given update function on the given services simultaneously and waits for a response, // within the supplied timeout. func updateKnServices(ctx context.Context, services []*cluster.KnativeService, diff --git a/api/turing/service/router_deployment_service_test.go b/api/turing/service/router_deployment_service_test.go index 548e32825..e4b31acac 100644 --- a/api/turing/service/router_deployment_service_test.go +++ b/api/turing/service/router_deployment_service_test.go @@ -353,12 +353,14 @@ func TestDeleteEndpoint(t *testing.T) { // Create mock controller controller := &mocks.Controller{} controller.On("DeleteKnativeService", mock.Anything, mock.Anything, - mock.Anything, mock.Anything).Return(nil) + mock.Anything, false).Return(nil) + controller.On("DeleteKubernetesDeployment", mock.Anything, mock.Anything, + mock.Anything, false).Return(nil) controller.On("DeleteKubernetesService", mock.Anything, mock.Anything, - mock.Anything, mock.Anything).Return(nil) - controller.On("DeleteSecret", mock.Anything, mock.Anything, mock.Anything).Return(nil) - controller.On("DeleteConfigMap", mock.Anything, mock.Anything).Return(nil) - controller.On("DeletePersistentVolumeClaim", mock.Anything, mock.Anything).Return(nil) + mock.Anything, false).Return(nil) + controller.On("DeleteSecret", mock.Anything, mock.Anything, false).Return(nil) + controller.On("DeleteConfigMap", mock.Anything, mock.Anything, false).Return(nil) + controller.On("DeletePersistentVolumeClaim", mock.Anything, mock.Anything, false).Return(nil) // Create test router version filePath := filepath.Join("..", "testdata", "cluster", @@ -404,14 +406,16 @@ func TestDeleteEndpoint(t *testing.T) { &merlin.Environment{Name: testEnv}, routerVersion, eventsCh, + false, ) assert.NoError(t, err) - controller.AssertCalled(t, "DeleteKubernetesService", "test-svc-fluentd-logger-1", testNs, timeout) - controller.AssertCalled(t, "DeleteConfigMap", "test-svc-fiber-config-1", testNs) - controller.AssertCalled(t, "DeleteKnativeService", "test-svc-enricher-1", testNs, timeout) - controller.AssertCalled(t, "DeleteKnativeService", "test-svc-ensembler-1", testNs, timeout) - controller.AssertCalled(t, "DeleteKnativeService", "test-svc-router-1", testNs, timeout) - controller.AssertCalled(t, "DeleteSecret", "test-svc-svc-acct-secret-1", testNs) - controller.AssertCalled(t, "DeletePersistentVolumeClaim", "pvc", testNs) + controller.AssertCalled(t, "DeleteKubernetesDeployment", "test-svc-fluentd-logger-1", testNs, timeout, false) + controller.AssertCalled(t, "DeleteKubernetesService", "test-svc-fluentd-logger-1", testNs, timeout, false) + controller.AssertCalled(t, "DeleteConfigMap", "test-svc-fiber-config-1", testNs, false) + controller.AssertCalled(t, "DeleteKnativeService", "test-svc-enricher-1", testNs, timeout, false) + controller.AssertCalled(t, "DeleteKnativeService", "test-svc-ensembler-1", testNs, timeout, false) + controller.AssertCalled(t, "DeleteKnativeService", "test-svc-router-1", testNs, timeout, false) + controller.AssertCalled(t, "DeleteSecret", "test-svc-svc-acct-secret-1", testNs, false) + controller.AssertCalled(t, "DeletePersistentVolumeClaim", "pvc", testNs, false) controller.AssertNumberOfCalls(t, "DeleteKnativeService", 3) } diff --git a/sdk/samples/router/general.py b/sdk/samples/router/general.py index 5e1407771..5292f39ed 100644 --- a/sdk/samples/router/general.py +++ b/sdk/samples/router/general.py @@ -50,6 +50,11 @@ def main(turing_api: str, project: str): id='ring-ding-ding', endpoint='http://fox-says.ring-ding-ding', timeout='20ms' + ), + Route( + id='control', + endpoint='http://fox-says.control', + timeout='20ms' ) ] @@ -169,14 +174,14 @@ def main(turing_api: str, project: str): # Create an enricher for the router enricher = Enricher( - image="ealen/echo-server:0.5.1", + image="docker.io/ealen/echo-server:0.5.1", resource_request=ResourceRequest( min_replica=0, max_replica=2, cpu_request="500m", memory_request="512Mi" ), - endpoint="/", + endpoint="/echo", timeout="60ms", port=3000, env=[ @@ -193,7 +198,7 @@ def main(turing_api: str, project: str): # have been created to assist you in constructing these objects - `StandardRouterEnsemblerConfig`, # `DockerRouterEnsemblerConfig` and `PyfuncRouterEnsemblerConfig`. ensembler = DockerRouterEnsemblerConfig( - image="ealen/echo-server:0.5.1", + image="docker.io/ealen/echo-server:0.5.1", resource_request=ResourceRequest( min_replica=1, max_replica=3, @@ -212,7 +217,7 @@ def main(turing_api: str, project: str): name="what-does-the-fox-say", routes=routes, rules=rules, - default_route_id="test", + default_route_id="control", experiment_engine=experiment_config, resource_request=resource_request, timeout="100ms",