CHE-7660 Fix cleaning up the OpenShift project (#8207)

6.19.x
Sergii Leshchenko 2018-01-10 17:08:55 +02:00 committed by GitHub
parent 76508e95c7
commit b3eb81fd9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 204 additions and 4 deletions

View File

@ -10,6 +10,7 @@
*/
package org.eclipse.che.workspace.infrastructure.openshift.project;
import com.google.common.annotations.VisibleForTesting;
import io.fabric8.kubernetes.api.model.PersistentVolumeClaim;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.api.model.Service;
@ -18,7 +19,10 @@ import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.Route;
import io.fabric8.openshift.client.OpenShiftClient;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.api.workspace.server.spi.InternalInfrastructureException;
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Defines an internal API for managing subset of objects inside {@link Project} instance.
@ -27,13 +31,32 @@ import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory
*/
public class OpenShiftProject {
private static final Logger LOG = LoggerFactory.getLogger(OpenShiftProject.class);
private final String workspaceId;
private final OpenShiftPods pods;
private final OpenShiftServices services;
private final OpenShiftRoutes routes;
private final OpenShiftPersistentVolumeClaims pvcs;
@VisibleForTesting
OpenShiftProject(
String workspaceId,
OpenShiftPods pods,
OpenShiftServices services,
OpenShiftRoutes routes,
OpenShiftPersistentVolumeClaims pvcs) {
this.workspaceId = workspaceId;
this.pods = pods;
this.services = services;
this.routes = routes;
this.pvcs = pvcs;
}
public OpenShiftProject(OpenShiftClientFactory clientFactory, String name, String workspaceId)
throws InfrastructureException {
this.workspaceId = workspaceId;
this.pods = new OpenShiftPods(name, workspaceId, clientFactory);
this.services = new OpenShiftServices(name, workspaceId, clientFactory);
this.routes = new OpenShiftRoutes(name, workspaceId, clientFactory);
@ -64,11 +87,35 @@ public class OpenShiftProject {
return pvcs;
}
/** Removes all object except persistent volume claim inside project. */
/** Removes all object except persistent volume claims inside project. */
public void cleanUp() throws InfrastructureException {
pods.delete();
services.delete();
routes.delete();
doRemove(pods::delete, services::delete, routes::delete);
}
/**
* Performs all the specified operations and throw exception with composite message if errors
* occurred while any operation execution
*/
private void doRemove(RemoveOperation... operations) throws InfrastructureException {
StringBuilder errors = new StringBuilder();
for (RemoveOperation operation : operations) {
try {
operation.perform();
} catch (InternalInfrastructureException e) {
LOG.warn(
"Internal infra error occurred while cleaning project up for workspace with id "
+ workspaceId,
e);
errors.append(" ").append(e.getMessage());
} catch (InfrastructureException e) {
errors.append(" ").append(e.getMessage());
}
}
if (errors.length() > 0) {
throw new InfrastructureException(
"Error(s) occurs while cleaning project up." + errors.toString());
}
}
private void create(String projectName, OpenShiftClient client) throws InfrastructureException {
@ -97,4 +144,8 @@ public class OpenShiftProject {
}
}
}
interface RemoveOperation {
void perform() throws InfrastructureException;
}
}

View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 2012-2017 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.che.workspace.infrastructure.openshift.project;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import io.fabric8.openshift.api.model.DoneableProjectRequest;
import io.fabric8.openshift.api.model.Project;
import io.fabric8.openshift.api.model.ProjectRequestFluent.MetadataNested;
import io.fabric8.openshift.client.OpenShiftClient;
import io.fabric8.openshift.client.dsl.ProjectRequestOperation;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
import org.eclipse.che.workspace.infrastructure.openshift.OpenShiftClientFactory;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
/**
* Tests {@link OpenShiftProject}
*
* @author Sergii Leshchenko
*/
@Listeners(MockitoTestNGListener.class)
public class OpenShiftProjectTest {
public static final String PROJECT_NAME = "testProject";
public static final String WORKSPACE_ID = "workspace123";
@Mock private OpenShiftPods pods;
@Mock private OpenShiftServices services;
@Mock private OpenShiftRoutes routes;
@Mock private OpenShiftPersistentVolumeClaims pvcs;
@Mock private OpenShiftClientFactory clientFactory;
@Mock private OpenShiftClient openShiftClient;
private OpenShiftProject openShiftProject;
@BeforeMethod
public void setUp() throws Exception {
when(clientFactory.create()).thenReturn(openShiftClient);
openShiftProject = new OpenShiftProject(WORKSPACE_ID, pods, services, routes, pvcs);
}
@Test
public void testOpenShiftProjectCreationWhenProjectExists() throws Exception {
// given
prepareProject(PROJECT_NAME);
// when
new OpenShiftProject(clientFactory, PROJECT_NAME, WORKSPACE_ID);
}
@Test
public void testOpenShiftProjectCreationWhenProjectDoesNotExist() throws Exception {
// given
MetadataNested projectMetadata = prepareProjectRequest();
Resource resource = prepareProjectResource(PROJECT_NAME);
doThrow(new KubernetesClientException("error", 403, null)).when(resource).get();
// when
OpenShiftProject openShiftProject =
new OpenShiftProject(clientFactory, PROJECT_NAME, WORKSPACE_ID);
// then
verify(projectMetadata).withName(PROJECT_NAME);
}
@Test
public void testOpenShiftProjectCleaningUp() throws Exception {
// when
openShiftProject.cleanUp();
verify(pods).delete();
verify(services).delete();
verify(routes).delete();
}
@Test
public void testOpenShiftProjectCleaningUpIfExceptionsOccurs() throws Exception {
doThrow(new InfrastructureException("err1.")).when(pods).delete();
doThrow(new InfrastructureException("err2.")).when(services).delete();
InfrastructureException error = null;
// when
try {
openShiftProject.cleanUp();
} catch (InfrastructureException e) {
error = e;
}
// then
assertNotNull(error);
String message = error.getMessage();
assertEquals(message, "Error(s) occurs while cleaning project up. err1. err2.");
verify(routes).delete();
}
private MetadataNested prepareProjectRequest() {
ProjectRequestOperation projectRequestOperation = mock(ProjectRequestOperation.class);
DoneableProjectRequest projectRequest = mock(DoneableProjectRequest.class);
MetadataNested metadataNested = mock(MetadataNested.class);
doReturn(projectRequestOperation).when(openShiftClient).projectrequests();
doReturn(projectRequest).when(projectRequestOperation).createNew();
doReturn(metadataNested).when(projectRequest).withNewMetadata();
doReturn(metadataNested).when(metadataNested).withName(anyString());
doReturn(projectRequest).when(metadataNested).endMetadata();
return metadataNested;
}
private Resource prepareProjectResource(String projectName) {
Resource projectResource = mock(Resource.class);
NonNamespaceOperation projectOperation = mock(NonNamespaceOperation.class);
doReturn(projectResource).when(projectOperation).withName(projectName);
doReturn(projectOperation).when(openShiftClient).projects();
openShiftClient.projects().withName(projectName).get();
return projectResource;
}
private void prepareProject(String projectName) {
Project project = mock(Project.class);
Resource projectResource = prepareProjectResource(projectName);
doReturn(project).when(projectResource).get();
}
}