From 95b22d8d074f294e997c27d79d369b0eb3bee9e2 Mon Sep 17 00:00:00 2001 From: davsad Date: Fri, 16 Jul 2021 09:44:22 +0100 Subject: [PATCH] Disable locking during deployment Issue-ID: SDC-3643 Signed-off-by: davsad Change-Id: I1a04c253d70bf5aebf33bba7b2b9f83bd559ae64 --- .../org/openecomp/sdc/be/servlets/LockServlet.java | 96 ++++++++++++++++ .../resources/scripts/sdcBePy/common/sdcBeProxy.py | 3 + .../resources/scripts/sdcBePy/tosca/imports/run.py | 25 +++-- .../openecomp/sdc/be/servlets/LockServletTest.java | 121 +++++++++++++++++++++ .../model/operations/api/IGraphLockOperation.java | 2 + .../model/operations/impl/GraphLockOperation.java | 23 ++-- 6 files changed, 252 insertions(+), 18 deletions(-) create mode 100644 catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LockServlet.java create mode 100644 catalog-be/src/test/java/org/openecomp/sdc/be/servlets/LockServletTest.java diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LockServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LockServlet.java new file mode 100644 index 0000000000..7319f7c060 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LockServlet.java @@ -0,0 +1,96 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.openecomp.sdc.be.servlets; + +import java.util.Arrays; + +import javax.inject.Inject; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.openecomp.sdc.be.components.impl.aaf.AafPermission; +import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed; +import org.openecomp.sdc.be.components.validation.UserValidations; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.user.Role; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode; +import org.openecomp.sdc.common.log.wrappers.Logger; +import org.springframework.stereotype.Controller; + +import com.jcabi.aspects.Loggable; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.servers.Server; +import io.swagger.v3.oas.annotations.tags.Tag; + + +@Loggable(prepend = true, value = Loggable.DEBUG, trim = false) +@Path("/v1/catalog") +@Tag(name = "SDCE-2 APIs") +@Server(url = "/sdc2/rest") +@Controller +public class LockServlet extends BeGenericServlet { + + private static final Logger log = Logger.getLogger(LockServlet.class); + private final UserValidations userValidations; + private final IGraphLockOperation graphLockOperation; + + @Inject + public LockServlet(final UserBusinessLogic userBusinessLogic, final ComponentsUtils componentsUtils, + final UserValidations userValidations, IGraphLockOperation graphLockOperation) { + super(userBusinessLogic, componentsUtils); + this.userValidations = userValidations; + this.graphLockOperation = graphLockOperation; + } + + @POST + @Path("/lock") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) + @Operation(description = "Toggle disable locking", method = "POST", responses = { + @ApiResponse(content = @Content(schema = @Schema(implementation = Response.class))), + @ApiResponse(responseCode = "200", description = "Disable locking successfully updated"), + @ApiResponse(responseCode = "500", description = "Update disable locking failed") + }) + public Response toggleDisableLocking(@Context final HttpServletRequest request, @HeaderParam("USER_ID") String userId, + @Parameter(description = "Disable Locking") boolean disable) { + log.info("User {} attempting to set disable locking with value {}", userId, disable); + userValidations.validateUserRole(userValidations.validateUserExists(userId), Arrays.asList(Role.DESIGNER, Role.ADMIN)); + try { + return Response.ok().entity(graphLockOperation.disableLocking(disable)).build(); + } catch (final Exception e) { + log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, LockServlet.class.getName(), "Failed to set disable locking", e); + return Response.serverError().build(); + } + } +} \ No newline at end of file diff --git a/catalog-be/src/main/resources/scripts/sdcBePy/common/sdcBeProxy.py b/catalog-be/src/main/resources/scripts/sdcBePy/common/sdcBeProxy.py index f2bef53564..0c71a382d1 100755 --- a/catalog-be/src/main/resources/scripts/sdcBePy/common/sdcBeProxy.py +++ b/catalog-be/src/main/resources/scripts/sdcBePy/common/sdcBeProxy.py @@ -49,6 +49,9 @@ class SdcBeProxy: 'consumerPassword': password })) + def disable_locking(self, disable): + return self.con.post("/sdc2/rest/v1/catalog/lock", disable) + def get_normatives(self): return self.con.get("/sdc2/rest/v1/screen", with_buffer=True) diff --git a/catalog-be/src/main/resources/scripts/sdcBePy/tosca/imports/run.py b/catalog-be/src/main/resources/scripts/sdcBePy/tosca/imports/run.py index 067f110efc..1df54ca50e 100644 --- a/catalog-be/src/main/resources/scripts/sdcBePy/tosca/imports/run.py +++ b/catalog-be/src/main/resources/scripts/sdcBePy/tosca/imports/run.py @@ -17,22 +17,27 @@ def main(sdc_be_proxy, update_version): # base_file_location = os.getcwd() + "/../../../import/tosca/" base_file_location = os.getcwd() + os.path.sep logger.debug("working directory =" + base_file_location) - - model_import_manager = ModelImportManager(Path(base_file_location) / 'models', ModelClient(sdc_be_proxy)) + if sdc_be_proxy.disable_locking("true") != 200: + raise RuntimeError("Failed to disable locking") try: - model_import_manager.create_models() + model_import_manager = ModelImportManager(Path(base_file_location) / 'models', ModelClient(sdc_be_proxy)) + try: + model_import_manager.create_models() + except Exception as ex: + logger.log("An error has occurred while uploading the models: ", str(ex)) + raise ex + process_element_list(normativeElementsList.get_normative_element_candidate_list(base_file_location), sdc_be_proxy) + process_type_list(normativeTypesList.get_normative_type_candidate_list(base_file_location), sdc_be_proxy, update_version) + process_element_list(normativeElementsList.get_normative_element_with_metadata_list(base_file_location), sdc_be_proxy) except Exception as ex: - logger.log("An error has occurred while uploading the models: ", str(ex)) + logger.log("An error has occurred while uploading elements and types: ", str(ex)) raise ex - - process_element_list(normativeElementsList.get_normative_element_candidate_list(base_file_location), sdc_be_proxy) - process_type_list(normativeTypesList.get_normative_type_candidate_list(base_file_location), sdc_be_proxy, update_version) - process_element_list(normativeElementsList.get_normative_element_with_metadata_list(base_file_location), sdc_be_proxy) - + finally: + if sdc_be_proxy.disable_locking("false") != 200: + raise RuntimeError("Failed to enable locking") logger.log("Script end ->", "All normatives imported successfully!") logger.print_and_exit(0, None) - def run(): sdc_be_proxy, update_version = parse_and_create_proxy() main(sdc_be_proxy, update_version) diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/LockServletTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/LockServletTest.java new file mode 100644 index 0000000000..c2fb235476 --- /dev/null +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/LockServletTest.java @@ -0,0 +1,121 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.openecomp.sdc.be.servlets; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response.Status; + +import org.glassfish.hk2.utilities.binding.AbstractBinder; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.glassfish.jersey.test.TestProperties; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.openecomp.sdc.be.components.validation.UserValidations; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.config.SpringConfig; +import org.openecomp.sdc.be.impl.ComponentsUtils; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.user.UserBusinessLogic; +import org.openecomp.sdc.common.api.ConfigurationSource; +import org.openecomp.sdc.common.api.Constants; +import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.openecomp.sdc.common.impl.FSConfigurationSource; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +class LockServletTest extends JerseyTest { + + @Mock + private HttpServletRequest request; + @Mock + private UserBusinessLogic userBusinessLogic; + @Mock + private ComponentsUtils componentsUtils; + @Mock + private IGraphLockOperation graphLockOperation; + @Mock + private UserValidations userValidations; + + private static final String postUrl = "/v1/catalog/lock"; + private static final String USER_ID = "cs0008"; + + @BeforeEach + void init() throws Exception { + super.setUp(); + initConfig(); + } + + @AfterEach + void destory() throws Exception { + super.tearDown(); + } + + private void initConfig() { + final String appConfigDir = "src/test/resources/config/catalog-be"; + final ConfigurationSource configurationSource = new FSConfigurationSource(ExternalConfiguration.getChangeListener(), appConfigDir); + final ConfigurationManager configurationManager = new ConfigurationManager(configurationSource); + final org.openecomp.sdc.be.config.Configuration configuration = new org.openecomp.sdc.be.config.Configuration(); + configuration.setJanusGraphInMemoryGraph(true); + configurationManager.setConfiguration(configuration); + ExternalConfiguration.setAppName("catalog-be"); + } + + @Override + protected ResourceConfig configure() { + MockitoAnnotations.openMocks(this); + forceSet(TestProperties.CONTAINER_PORT, "0"); + final ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); + return new ResourceConfig(LockServlet.class) + .register(new AbstractBinder() { + @Override + protected void configure() { + bind(request).to(HttpServletRequest.class); + bind(userBusinessLogic).to(UserBusinessLogic.class); + bind(componentsUtils).to(ComponentsUtils.class); + bind(graphLockOperation).to(IGraphLockOperation.class); + bind(userValidations).to(UserValidations.class); + } + }) + .property("contextConfig", context); + } + + @Test + void disableLockTest() { + assertEquals(Status.OK.getStatusCode(), postDisableLock(true)); + assertEquals(Status.OK.getStatusCode(), postDisableLock(false)); + assertEquals(Status.OK.getStatusCode(), postDisableLock("true")); + assertEquals(Status.OK.getStatusCode(), postDisableLock("false")); + assertEquals(Status.BAD_REQUEST.getStatusCode(), postDisableLock("true1")); + assertEquals(Status.BAD_REQUEST.getStatusCode(), postDisableLock(null)); + } + + private int postDisableLock(Object disable) { + return target(postUrl).request(MediaType.APPLICATION_JSON) + .header(Constants.USER_ID_HEADER, USER_ID) + .post(Entity.json(disable)).getStatus(); + } +} \ No newline at end of file diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IGraphLockOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IGraphLockOperation.java index 21288168b3..3e4152728d 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IGraphLockOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/IGraphLockOperation.java @@ -30,4 +30,6 @@ public interface IGraphLockOperation { StorageOperationStatus lockComponentByName(String name, NodeTypeEnum nodeType); StorageOperationStatus unlockComponentByName(String name, String componentId, NodeTypeEnum nodeType); + + boolean disableLocking(final boolean disable); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/GraphLockOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/GraphLockOperation.java index 0106cd3529..bc49c8aaec 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/GraphLockOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/GraphLockOperation.java @@ -27,17 +27,17 @@ import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.common.log.wrappers.Logger; import org.springframework.stereotype.Component; +import lombok.NoArgsConstructor; + @Component("graph-lock-operation") +@NoArgsConstructor public class GraphLockOperation implements IGraphLockOperation { private static final Logger log = Logger.getLogger(GraphLockOperation.class.getName()); + private boolean disable = false; @javax.annotation.Resource private JanusGraphGenericDao janusGraphGenericDao; - public GraphLockOperation() { - super(); - } - /* * (non-Javadoc) * @@ -48,7 +48,7 @@ public class GraphLockOperation implements IGraphLockOperation { log.info("lock resource with id {}", componentId); JanusGraphOperationStatus lockElementStatus = null; try { - lockElementStatus = janusGraphGenericDao.lockElement(componentId, nodeType); + lockElementStatus = disable ? JanusGraphOperationStatus.OK : janusGraphGenericDao.lockElement(componentId, nodeType); } catch (Exception e) { lockElementStatus = JanusGraphOperationStatus.ALREADY_LOCKED; } @@ -62,13 +62,13 @@ public class GraphLockOperation implements IGraphLockOperation { */ @Override public StorageOperationStatus unlockComponent(String componentId, NodeTypeEnum nodeType) { - JanusGraphOperationStatus lockElementStatus = janusGraphGenericDao.releaseElement(componentId, nodeType); + JanusGraphOperationStatus lockElementStatus = disable ? JanusGraphOperationStatus.OK : janusGraphGenericDao.releaseElement(componentId, nodeType); return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(lockElementStatus); } @Override public StorageOperationStatus unlockComponentByName(String name, String componentId, NodeTypeEnum nodeType) { - JanusGraphOperationStatus lockElementStatus = janusGraphGenericDao.releaseElement(name, nodeType); + JanusGraphOperationStatus lockElementStatus = disable ? JanusGraphOperationStatus.OK : janusGraphGenericDao.releaseElement(name, nodeType); return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(lockElementStatus); } @@ -77,10 +77,17 @@ public class GraphLockOperation implements IGraphLockOperation { log.info("lock resource with name {}", name); JanusGraphOperationStatus lockElementStatus = null; try { - lockElementStatus = janusGraphGenericDao.lockElement(name, nodeType); + lockElementStatus = disable ? JanusGraphOperationStatus.OK : janusGraphGenericDao.lockElement(name, nodeType); } catch (Exception e) { lockElementStatus = JanusGraphOperationStatus.ALREADY_LOCKED; } return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(lockElementStatus); } + + @Override + public boolean disableLocking(boolean disable) { + log.info("Toggling disable locking from {} to {}", this.disable, disable); + this.disable = disable; + return this.disable; + } } -- 2.16.6