Skip to content
4 changes: 0 additions & 4 deletions openapi/openapi-component_provisioner-v1.0.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,6 @@ paths:
type: string
description: The bitbucket repository url for the provisioned component.
example: "https://bitbucket.com/projects/myproject/repos/repo_name"
accessToken:
type: string
description: The access token for the provisioned component.
example: "secret-access-token"
responses:
"200":
description: Provisioning completion notified.
Expand Down
20 changes: 0 additions & 20 deletions openapi/openapi-projects-info-service-v1.0.0.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,6 @@ paths:
description: >
This endpoint receives an azure token, and returns all the groups associated to the user.
operationId: getAzureGroups
parameters:
- name: token
in: header
required: true
schema:
type: string
description: Azure token used to get the groups.
responses:
"200":
description: List of azure groups associated to the user.
Expand Down Expand Up @@ -77,13 +70,6 @@ paths:
Get all the projects a user get access to. For that, first of all it will get all the azure groups associated to the user,
and then it will get all the projects associated to those groups.
operationId: getProjects
parameters:
- name: token
in: header
required: true
schema:
type: string
description: Azure token used to get the groups.
responses:
"200":
description: List of projects the user has access to.
Expand Down Expand Up @@ -120,12 +106,6 @@ paths:
Get all project info and cluster for a given project key.
operationId: getProjectClusters
parameters:
- name: token
in: header
required: true
schema:
type: string
description: Azure token used to get the groups.
- name: projectKey
in: path
required: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.opendevstack.component_provisioner.server.model.NotifyProvisioningStatusUpdateRequest;
import org.opendevstack.component_provisioner.server.model.ProvisionActionResponse;
import org.opendevstack.component_provisioner.server.model.ProvisioningDeleteRequest;
import org.opendevstack.component_provisioner.server.services.AuthenticationProvider;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -17,25 +18,28 @@
@Slf4j
public class ProvisionResultsApiController implements ProvisionResultsApi {

private final AuthenticationProvider authenticationProvider;
private final ProvisionResultsApiFacade provisionResultsApiFacade;

public ProvisionResultsApiController(ProvisionResultsApiFacade provisionResultsApiFacade) {
public ProvisionResultsApiController(AuthenticationProvider authenticationProvider, ProvisionResultsApiFacade provisionResultsApiFacade) {
this.authenticationProvider = authenticationProvider;
this.provisionResultsApiFacade = provisionResultsApiFacade;
}

@Override
public ResponseEntity<Void> notifyProvisioningStatusUpdate(String projectKey, String status, NotifyProvisioningStatusUpdateRequest notifyProvisioningCompletedRequest) {
log.debug("Notifying provision status update. ProjectKey: {}, Status: {}, notifyProvisioningCompletedRequest: {}", projectKey, status, notifyProvisioningCompletedRequest);

var accessToken = authenticationProvider.getAccessToken();

provisionResultsApiFacade.validate(projectKey, status);

provisionResultsApiFacade.notifyProvisioningStatusUpdate(projectKey,
ProjectComponentStatus.valueOf(status),
notifyProvisioningCompletedRequest.getComponentId(),
notifyProvisioningCompletedRequest.getCatalogItemId(),
notifyProvisioningCompletedRequest.getComponentUrl(),
provisionResultsApiFacade.getIdToken(),
notifyProvisioningCompletedRequest.getAccessToken());
accessToken);

return ResponseEntity.ok().build();
}
Expand All @@ -44,7 +48,9 @@ public ResponseEntity<Void> notifyProvisioningStatusUpdate(String projectKey, St
public ResponseEntity<Void> deleteProvisioningStatus(String projectKey, ProvisioningDeleteRequest provisioningDeleteRequest) {
log.debug("Delete provisioning status. ProjectKey: {}, provisioningDeleteRequest: {}", projectKey, provisioningDeleteRequest);

provisionResultsApiFacade.deleteProvisioningStatus(projectKey, provisioningDeleteRequest.getComponentId(), provisionResultsApiFacade.getIdToken());
var accessToken = authenticationProvider.getAccessToken();

provisionResultsApiFacade.deleteProvisioningStatus(projectKey, provisioningDeleteRequest.getComponentId(), accessToken);

return ResponseEntity.ok().build();
}
Expand All @@ -53,25 +59,26 @@ public ResponseEntity<Void> deleteProvisioningStatus(String projectKey, Provisio
public ResponseEntity<ProvisionActionResponse> createIncident(String projectKey, String componentId, CreateIncidentAction createIncidentAction) {
log.debug("Creating incident. ProjectKey: {}, componentId: {}, CreateIncidentAction: {}", projectKey, componentId, createIncidentAction);

var idToken = provisionResultsApiFacade.getIdToken();
var accessToken = authenticationProvider.getAccessToken();

provisionResultsApiFacade.validate(projectKey, componentId, createIncidentAction);
provisionResultsApiFacade.addSystemParametersToAction(projectKey, createIncidentAction);

var isInDeletingState = provisionResultsApiFacade.isInDeletingState(projectKey, componentId, idToken, createIncidentAction);
var isInDeletingState = provisionResultsApiFacade.isInDeletingState(projectKey, componentId, accessToken);

if (isInDeletingState) {
log.debug("Project component already in DELETING state, skipping create of the incident via AWX");

return ResponseEntity.ok().build();
} else {
log.debug("Setting state to DELETING");

provisionResultsApiFacade.notifyProvisioningStatusUpdate(projectKey,
ProjectComponentStatus.DELETING,
componentId,
null,
null,
provisionResultsApiFacade.getIdToken(),
null);
accessToken);

log.debug("Creating incident via AWX");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import java.util.function.Function;
import java.util.stream.Collectors;

import static org.opendevstack.component_provisioner.server.controllers.validators.ProvisionerActionsApiValidator.getAccessToken;
import static org.opendevstack.component_provisioner.server.controllers.validators.ProvisionerActionsApiValidator.getCatalogItemId;
import static org.opendevstack.component_provisioner.server.controllers.validators.ProvisionerActionsApiValidator.getParameterString;
import static org.opendevstack.component_provisioner.server.controllers.validators.ProvisionerActionsApiValidator.getProjectKey;
Expand All @@ -35,12 +34,11 @@

public void validate(ProvisionAction provisionAction) {
var projectKey = getProjectKey(provisionAction);
var accessToken = getAccessToken(provisionAction);
var catalogItemId = getCatalogItemId(provisionAction);
var idToken = authenticationProvider.getIdToken();
var accessToken = authenticationProvider.getAccessToken();
var location = getLocation(provisionAction);

var catalogItem = componentCatalogService.getCatalogItem(idToken, accessToken, catalogItemId, projectKey);
var catalogItem = componentCatalogService.getCatalogItem(accessToken, catalogItemId, projectKey);
var provisionUserAction = Optional.ofNullable(catalogItem)
.map(CatalogItem::getUserActions)
.map(userActions -> userActions.stream()
Expand Down Expand Up @@ -99,9 +97,10 @@
return param.getOptions() == null || param.getOptions().isEmpty();
}

private boolean isListType(ProvisionActionParameter param) {
return MandatoryFieldType.SINGLELIST.getValue().equalsIgnoreCase(param.getType())
|| MandatoryFieldType.MULTIPLELIST.getValue().equalsIgnoreCase(param.getType());
private boolean isListTypeAnswer(ProvisionActionParameter param) {
// MULTIPLELIST is the only type that stores multiple values as a list for the answers;

Check warning on line 101 in src/main/java/org/opendevstack/component_provisioner/server/controllers/validators/MandatoryFieldsValidator.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This block of commented-out lines of code should be removed.

See more on https://sonarcloud.io/project/issues?id=opendevstack_ods-component-provisioner&issues=AZ2WsBp86QkuPrAXeBN4&open=AZ2WsBp86QkuPrAXeBN4&pullRequest=19
// SINGLELIST and STRING types store single string values for the answer.
return MandatoryFieldType.MULTIPLELIST.getValue().equalsIgnoreCase(param.getType());
}

private void applyDefaultValue(
Expand Down Expand Up @@ -142,7 +141,7 @@
ProvisionActionParameter param,
CatalogItemUserActionParameter catalogParam
) {
if (isListType(param)) {
if (isListTypeAnswer(param)) {
validateListValues(param, catalogParam);
} else {
validateSingleValue(param, catalogParam);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,19 @@ public void validate(ProvisionAction provisionAction) {
log.debug("Start validation for provisionActions: {}", provisionAction);

var projectKey = getProjectKey(provisionAction);
var accessToken = getAccessToken(provisionAction);
var componentId = getComponentId(provisionAction);
var idToken = authenticationProvider.getIdToken();
var accessToken = authenticationProvider.getAccessToken();

validateInputParams(projectKey, accessToken, componentId);

validateComponentIsNotProvisioned(projectKey, idToken, accessToken, componentId);
validateComponentIsNotProvisioned(projectKey, accessToken, componentId);

validateUserHasPermissionsToProvision(projectKey, idToken, accessToken);
validateUserHasPermissionsToProvision(projectKey, accessToken);

mandatoryFieldsValidator.validate(provisionAction);
}

private void validateUserHasPermissionsToProvision(String projectKey, String idToken, String accessToken) {
private void validateUserHasPermissionsToProvision(String projectKey, String accessToken) {
log.debug("Validating user has permissions to provision. projectKey: {}", projectKey);

CatalogItemUserActionGroupsRestriction catalogItemUserActionGroupsRestriction = CatalogItemUserActionGroupsRestriction.builder()
Expand All @@ -63,7 +62,7 @@ private void validateUserHasPermissionsToProvision(String projectKey, String idT
.build();
EvaluationRestrictions restrictions = new EvaluationRestrictions(projectKey, userActionEntityRestrictions);

List<String> userGroups = projectsInfoService.getProjectGroups(idToken, accessToken);
List<String> userGroups = projectsInfoService.getProjectGroups(accessToken);
RestrictionsParams params = RestrictionsParams.builder()
.projectKey(projectKey)
.userGroups(userGroups)
Expand All @@ -82,10 +81,10 @@ private void validateUserHasPermissionsToProvision(String projectKey, String idT
}
}

private void validateComponentIsNotProvisioned(String projectKey, String idToken, String accessToken, String componentId) {
private void validateComponentIsNotProvisioned(String projectKey, String accessToken, String componentId) {
log.debug("Validating component is not provisioned. projectKey: {}, componentId: {}", projectKey, componentId);

var projectComponents = componentCatalogService.getProjectComponents(projectKey, idToken, accessToken);
var projectComponents = componentCatalogService.getProjectComponents(projectKey, accessToken);

var componentIdAlreadyProvisioned = projectComponents.stream()
.filter(projectComponent -> projectComponent.getComponentId() != null)
Expand All @@ -112,10 +111,6 @@ protected static String getProjectKey(ProvisionAction provisionAction) {
return getParameterString(provisionAction, "project_key");
}

protected static String getAccessToken(ProvisionAction provisionAction) {
return getParameterString(provisionAction, "access_token");
}

protected static String getCatalogItemId(ProvisionAction provisionAction) {
return getParameterString(provisionAction, "catalog_item_id");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.opendevstack.component_provisioner.server.controllers.exceptions.InvalidRestEntityException;
import org.opendevstack.component_provisioner.server.controllers.exceptions.ProjectConfigurationException;
import org.opendevstack.component_provisioner.server.controllers.model.ProjectComponentStatus;
import org.opendevstack.component_provisioner.server.controllers.model.awx.AwxResponse;
import org.opendevstack.component_provisioner.server.controllers.validators.ParameterType;
Expand All @@ -13,6 +14,7 @@
import org.opendevstack.component_provisioner.server.services.AuthenticationProvider;
import org.opendevstack.component_provisioner.server.services.AwxService;
import org.opendevstack.component_provisioner.server.services.ComponentCatalogService;
import org.opendevstack.component_provisioner.server.services.ProjectsInfoService;
import org.opendevstack.component_provisioner.server.services.ProvisionService;
import org.opendevstack.component_provisioner.server.services.awx.AwxWorkflowJobLaunch;
import org.springframework.beans.factory.annotation.Value;
Expand All @@ -24,13 +26,12 @@
@Slf4j
public class ProvisionResultsApiFacade {

public static final String ACCESS_TOKEN_PARAMETER_NAME = "access_token";

private final AwxService awxService;
private final ComponentCatalogService componentCatalogService;
private final EntitiesMapper entitiesMapper;
private final ProvisionService provisionService;
private final AuthenticationProvider authenticationProvider;
private final ProjectsInfoService projectsInfoService;


@Value("${component-provisioner.support.create-incident-workflow-id:WORKFLOW}")
Expand All @@ -40,18 +41,19 @@ public ProvisionResultsApiFacade(AwxService awxService,
ComponentCatalogService componentCatalogService,
EntitiesMapper entitiesMapper,
ProvisionService provisionService,
AuthenticationProvider authenticationProvider) {
AuthenticationProvider authenticationProvider,
ProjectsInfoService projectsInfoService) {
this.awxService = awxService;
this.componentCatalogService = componentCatalogService;
this.entitiesMapper = entitiesMapper;
this.provisionService = provisionService;
this.authenticationProvider = authenticationProvider;
this.projectsInfoService = projectsInfoService;
}

public boolean isInDeletingState(String projectKey, String componentId, String idToken, CreateIncidentAction createIncidentAction) {
var accessToken = getParameterString(createIncidentAction, ACCESS_TOKEN_PARAMETER_NAME);
public boolean isInDeletingState(String projectKey, String componentId, String accessToken) {

var projectComponents = componentCatalogService.getProjectComponents(projectKey, idToken, accessToken);
var projectComponents = componentCatalogService.getProjectComponents(projectKey, accessToken);

return projectComponents.stream()
.filter(component -> component.getComponentId() != null)
Expand All @@ -76,16 +78,12 @@ public AwxResponse requestProvisionToAwx(String projectKey, String componentId,
}

public void notifyProvisioningStatusUpdate(String projectKey, ProjectComponentStatus status, String componentId,
String catalogItemId, String componentUrl, String idToken, String accessToken) {
provisionService.notifyProvisioningStatusUpdate(projectKey, status, componentId, catalogItemId, componentUrl, idToken, accessToken);
}

public void deleteProvisioningStatus(String projectKey, String componentId, String idToken) {
provisionService.deleteProvisioningStatus(projectKey, componentId, idToken);
String catalogItemId, String componentUrl, String accessToken) {
provisionService.notifyProvisioningStatusUpdate(projectKey, status, componentId, catalogItemId, componentUrl, accessToken);
}

public String getIdToken() {
return authenticationProvider.getIdToken();
public void deleteProvisioningStatus(String projectKey, String componentId, String accessToken) {
provisionService.deleteProvisioningStatus(projectKey, componentId, accessToken);
}

public void validate(String projectKey, String status) {
Expand All @@ -102,30 +100,49 @@ public void validate(String projectKey, String status) {
}

public void validate(String projectKey, String componentId, CreateIncidentAction createIncidentAction) {
var caller = getParameterString(createIncidentAction, "caller");
var clusterLocation = getParameterString(createIncidentAction, "cluster_location");
var isDeployed = getParameterString(createIncidentAction, "is_deployed");
var changeNumber = getParameterString(createIncidentAction, "change_number");
var reason = getParameterString(createIncidentAction, "reason");

var accessToken = getParameterString(createIncidentAction, ACCESS_TOKEN_PARAMETER_NAME);

var mainParamsAreEmpty = StringUtils.isBlank(projectKey) || StringUtils.isBlank(componentId);
var extraParamsAreEmtpy = StringUtils.isBlank(caller) || StringUtils.isBlank(clusterLocation) || StringUtils.isBlank(isDeployed)
var extraParamsAreEmtpy = StringUtils.isBlank(isDeployed)
|| StringUtils.isBlank(changeNumber) || StringUtils.isBlank(reason);
var tokenIsEmpty = StringUtils.isBlank(accessToken);

if (mainParamsAreEmpty) {
throw new InvalidRestEntityException("project_key, component_id are required.");
}

if (extraParamsAreEmtpy) {
throw new InvalidRestEntityException("caller, cluster_location, is_deployed, change_number and reason are required.");
throw new InvalidRestEntityException("is_deployed, change_number and reason are required.");
}
}

if (tokenIsEmpty) {
throw new InvalidRestEntityException("access_token is required.");
public void addSystemParametersToAction(String projectKey, CreateIncidentAction action) {
addClusterLocationParameter(projectKey, action);
addCallerParameter(action);
}

private void addClusterLocationParameter(String projectKey, CreateIncidentAction action) {
var accessToken = authenticationProvider.getAccessToken();
var clusters = projectsInfoService.getProjectClusters(accessToken, projectKey).getClusters();
if (clusters.isEmpty()) {
throw new ProjectConfigurationException("Cannot retrieve the current project location for project: " + projectKey);
}
var clusterLocation = clusters.getFirst();
action.addParametersItem(CreateIncidentParameter.builder()
.name("cluster_location")
.type(ParameterType.STRING.getValue())
.value(clusterLocation)
.build());
}

private void addCallerParameter(CreateIncidentAction action) {
var caller = authenticationProvider.getUserPrincipalName();
action.addParametersItem(CreateIncidentParameter.builder()
.name("caller")
.type(ParameterType.STRING.getValue())
.value(caller)
.build());
}

public String getParameterString(CreateIncidentAction createIncidentAction, String parameterName) {
Expand Down
Loading
Loading