Skip to content

Commit

Permalink
Merge pull request #1180 from PublicisSapient/DTS-38481-jira-permissi…
Browse files Browse the repository at this point in the history
…on-error

DTS-38481:Read exception should fail processing | <Release 10.1.0>
  • Loading branch information
shunaray committed Jul 31, 2024
2 parents 8237c78 + 42b5007 commit 6305db8
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 54 deletions.
135 changes: 86 additions & 49 deletions UI/src/app/config/advanced-settings/advanced-settings.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,37 +39,36 @@
<div class="content select-scenario" *ngIf="selectedView === 'processor_state'">

<p-table [value]="processorData.data" [paginator]="true" [rows]="15" [loading]="dataLoading"
styleClass="p-datatable-striped" loadingIcon="loading-img" [autoLayout]="true">
styleClass="p-datatable-striped" loadingIcon="loading-img" [autoLayout]="true">

<ng-template pTemplate="caption">
<div class="table-header">
Processors
<div class="d-flex align-items-center">
<span style="font-size: 0.8em;">
Select Project
</span>
<span class="p-mr-3 p-ml-3">
<p-dropdown [options]="userProjects" [(ngModel)]="selectedProject" optionLabel="name"
[style]="{'min-width':'300px', 'max-width':'300px'}" [panelStyle]="{'min-width':'inherit', 'max-width':'inherit'}"
[filter]="true" filterBy="name" [showClear]="false" placeholder="Select a Project"
(onChange)="updateProjectSelection($event)"
>
<ng-template pTemplate="selectedItem">
<div class="userProject-item userProject-item-value" *ngIf="selectedProject">
<div>{{selectedProject.name}}</div>
</div>
</ng-template>
<ng-template let-userProject pTemplate="item">
<div class="userProject-item">
<div>{{userProject.name}}</div>
</div>
</ng-template>
</p-dropdown>
</span>
<span style="font-size: 0.8em;">
Select Project
</span>
<span class="p-mr-3 p-ml-3">
<p-dropdown [options]="userProjects" [(ngModel)]="selectedProject" optionLabel="name"
[style]="{'min-width':'300px', 'max-width':'300px'}"
[panelStyle]="{'min-width':'inherit', 'max-width':'inherit'}" [filter]="true" filterBy="name"
[showClear]="false" placeholder="Select a Project" (onChange)="updateProjectSelection($event)">
<ng-template pTemplate="selectedItem">
<div class="userProject-item userProject-item-value" *ngIf="selectedProject">
<div>{{selectedProject.name}}</div>
</div>
</ng-template>
<ng-template let-userProject pTemplate="item">
<div class="userProject-item">
<div>{{userProject.name}}</div>
</div>
</ng-template>
</p-dropdown>
</span>

</div>
</div>
</div>
</ng-template>
</ng-template>
<ng-template pTemplate="header">
<tr>
<th id="processorName">Processor Name</th>
Expand All @@ -86,33 +85,44 @@
</td>

<td class='custom-table-cell'>
<span *ngIf="(!findTraceLogForTool(processor.processorName)?.executionOngoing && processor.processorName === 'Jira') || processor.processorName !== 'Jira'">{{ showExecutionDate(processor.processorName) }}</span>
<span
*ngIf="(!findTraceLogForTool(processor.processorName)?.executionOngoing && processor.processorName === 'Jira') || processor.processorName !== 'Jira'">{{
showExecutionDate(processor.processorName) }}</span>
</td>
<td class="custom-table-cell">
<p-progressBar mode="indeterminate" *ngIf="processor.processorName === 'Jira' && findTraceLogForTool(processor.processorName)?.executionOngoing === true " [style]="{ height: '6px' }"></p-progressBar>
<p-progressBar mode="indeterminate"
*ngIf="processor.processorName === 'Jira' && findTraceLogForTool(processor.processorName)?.executionOngoing === true "
[style]="{ height: '6px' }"></p-progressBar>
</td>
<td class='custom-table-cell'>
<div class="p-d-flex p-align-center">

<div class="p-d-flex p-align-center" *ngIf="(!findTraceLogForTool(processor.processorName)?.executionOngoing && processor.processorName === 'Jira') || processor.processorName !== 'Jira'">

<div class="p-d-flex p-align-center"
*ngIf="(!findTraceLogForTool(processor.processorName)?.executionOngoing && processor.processorName === 'Jira') || processor.processorName !== 'Jira'">
<div *ngIf="showProcessorLastState(processor.processorName) !== 'NA'" class="status-container"
[ngClass]="showProcessorLastState(processor.processorName) === 'Success' ? 'active' : 'inactive'">
{{ showProcessorLastState(processor.processorName)}}
</div>
<span *ngIf="showProcessorLastState(processor.processorName) === 'NA'">NA</span>
</div>
<div class="p-ml-2" *ngIf="processor.processorName === 'Jira'">
<i class="pi pi-info-circle" [ngClass]="{'disabled': !(findTraceLogForTool('Jira')?.progressStatusList?.length || findTraceLogForTool('Jira')?.errorMessage)}"
(click)="(findTraceLogForTool('Jira')?.errorMessage || findTraceLogForTool('Jira')?.progressStatusList?.length) ? op.toggle($event) : ''" style="font-size: 1.2rem"></i>
<div class="p-ml-2" *ngIf="processor.processorName === 'Jira'">
<i class="pi pi-info-circle"
[ngClass]="{'disabled': !(findTraceLogForTool('Jira')?.progressStatusList?.length || findTraceLogForTool('Jira')?.errorMessage)}"
(click)="(findTraceLogForTool('Jira')?.errorMessage || findTraceLogForTool('Jira')?.progressStatusList?.length) ? op.toggle($event) : ''"
style="font-size: 1.2rem"></i>
</div>
</div>
</div>
</td>
<td class='custom-table-cell p-d-flex p-align-center column-width'>
<button pButton pRipple label="Run Now"
icon="{{findTraceLogForTool(processor.processorName)?.executionOngoing === true ? 'pi pi-spin pi-spinner' : 'pi pi-forward'}}"
[disabled]="(shouldDisableRunProcessor() || findTraceLogForTool(processor.processorName)?.executionOngoing === true) && processor.processorName !== 'Jira' "
class="p-button-sm p-button-success p-button-raised" (click)="runProcessor(processor.processorName)"></button>
<div class="action-btns p-ml-3" [ngClass]="{'disabled':!(getToolDetailsForProcessor(processor?.processorName)?.length > 0 && findTraceLogForTool(processor?.processorName)) || findTraceLogForTool(processor?.processorName)?.isDeleteDisable}" *ngIf="!shouldDisableRunProcessor()"><i class="far fa-trash-alt" (click)="deleteProcessorData(processor)"></i></div>
class="p-button-sm p-button-success p-button-raised"
(click)="runProcessor(processor.processorName)"></button>
<div class="action-btns p-ml-3"
[ngClass]="{'disabled':!(getToolDetailsForProcessor(processor?.processorName)?.length > 0 && findTraceLogForTool(processor?.processorName)) || findTraceLogForTool(processor?.processorName)?.isDeleteDisable}"
*ngIf="!shouldDisableRunProcessor()"><i class="far fa-trash-alt"
(click)="deleteProcessorData(processor)"></i></div>
</td>
</tr>
</ng-template>
Expand All @@ -131,34 +141,61 @@

<p-confirmDialog #cd [transitionOptions]="'0ms'">
<p-footer>
<button type="button" (click)="cd.accept()" pButton label="Yes"></button>
<button type="button" (click)="cd.reject()" pButton label="No"></button>
<button type="button" (click)="cd.accept()" pButton label="Yes"></button>
<button type="button" (click)="cd.reject()" pButton label="No"></button>
</p-footer>
</p-confirmDialog>

<p-overlayPanel #op [showCloseIcon]="false">
<div class="progress-dialog-body p-mb-4">
<section *ngIf="findTraceLogForTool('Jira')?.progressStatusList?.length && !(findTraceLogForTool('Jira')?.errorMessage); else logError">
<h3>Progress Stats:</h3>
<p-table [value]="findTraceLogForTool('Jira')?.progressStatusList" [tableStyle]="{ 'min-width': '40rem' }"
[scrollable]="true" scrollHeight="200px" *ngIf="findTraceLogForTool('Jira')?.progressStatusList?.length && !(findTraceLogForTool('Jira')?.errorMessage) ; else logError">
[scrollable]="true" scrollHeight="200px">
<ng-template pTemplate="header">
<tr>
<th>Step Name</th>
<th>End Time</th>
<th>Status</th>
</tr>
<tr>
<th>Step Name</th>
<th>End Time</th>
<th>Status</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-item>
<tr>
<td>{{item.stepName}}</td>
<td>{{endTimeConversion(item?.endTime)}}</td>
<td>{{item.status}}</td>
</tr>

<tr>
<td>{{item.stepName}}</td>
<td>{{endTimeConversion(item?.endTime)}}</td>
<td>{{item.status}}</td>
</tr>
</ng-template>
</p-table>
</p-table>
</section>

<ng-template #logError>
<h3 class="p-text-center" class="error-text"><img src="../../../assets/img/icon-failure.svg" alt="Failure" class="p-mr-1" />{{ findTraceLogForTool('Jira')?.errorMessage}}</h3>
</ng-template>

<section *ngIf="findTraceLogForTool('Jira')?.errorDetailList?.length > 0">
<h3>Errors:</h3>
<p-table [value]="findTraceLogForTool('Jira')?.errorDetailList" [tableStyle]="{ 'min-width': '40rem' }"
[scrollable]="true" scrollHeight="200px">
<ng-template pTemplate="header">
<tr>
<th>URL</th>
<th>Impact</th>
<th>Status</th>
<th>Error</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-item>
<tr>
<td style="word-break: break-all">{{item.url}}</td>
<td>{{item.impact}}</td>
<td>{{item.status}}</td>
<td>{{item.error}}</td>
</tr>
</ng-template>
</p-table>
</section>

<ul class="p-pr-1 p-pl-0 list-style-none" *ngIf="dataMismatchObj['Jira']">
<li class="tooltip-item p-d-flex p-pt-2">
<div class="icon-container">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.core.mapping.Document;

import com.publicissapient.kpidashboard.common.model.application.ErrorDetail;
import com.publicissapient.kpidashboard.common.model.application.ProgressStatus;

import lombok.Data;
Expand Down Expand Up @@ -58,4 +59,6 @@ public class ProcessorExecutionTraceLog {
private String errorMessage;
private String failureLog;
private List<ProgressStatus> progressStatusList;
//save any resource not found error
private List<ErrorDetail> errorDetailList;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2014 CapitalOne, LLC.
* Further development Copyright 2022 Sapient Corporation.
*
* 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.
*/

package com.publicissapient.kpidashboard.common.model.application;

import lombok.Data;

@Data
public class ErrorDetail {
private int status;
private String url;
private String impact;
private String error;

public ErrorDetail(int status, String url, String error, String impact) {
this.status = status;
this.url = url;
this.impact = impact;
this.error = error;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.bson.types.ObjectId;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
Expand All @@ -55,10 +56,13 @@
import com.atlassian.jira.rest.client.api.domain.SearchResult;
import com.publicissapient.kpidashboard.common.client.KerberosClient;
import com.publicissapient.kpidashboard.common.exceptions.ClientErrorMessageEnum;
import com.publicissapient.kpidashboard.common.model.ProcessorExecutionTraceLog;
import com.publicissapient.kpidashboard.common.model.ToolCredential;
import com.publicissapient.kpidashboard.common.model.application.ErrorDetail;
import com.publicissapient.kpidashboard.common.model.application.ProjectVersion;
import com.publicissapient.kpidashboard.common.model.connection.Connection;
import com.publicissapient.kpidashboard.common.processortool.service.ProcessorToolConnectionService;
import com.publicissapient.kpidashboard.common.repository.tracelog.ProcessorExecutionTraceLogRepository;
import com.publicissapient.kpidashboard.common.service.AesEncryptionService;
import com.publicissapient.kpidashboard.common.service.ToolCredentialProvider;
import com.publicissapient.kpidashboard.common.util.DateUtil;
Expand Down Expand Up @@ -91,6 +95,8 @@ public class JiraCommonService {
private AesEncryptionService aesEncryptionService;
@Autowired
private ProcessorToolConnectionService processorToolConnectionService;
@Autowired
private ProcessorExecutionTraceLogRepository processorExecutionTraceLogRepository;

/**
* @param projectConfig
Expand All @@ -106,6 +112,7 @@ public class JiraCommonService {
public String getDataFromClient(ProjectConfFieldMapping projectConfig, URL url, KerberosClient krb5Client)
throws IOException {
Optional<Connection> connectionOptional = projectConfig.getJira().getConnection();
ObjectId projectConfigId = projectConfig.getBasicProjectConfigId();
boolean spenagoClient = connectionOptional.map(Connection::isJaasKrbAuth).orElse(false);
if (spenagoClient) {
HttpUriRequest request = RequestBuilder.get().setUri(url.toString())
Expand All @@ -114,7 +121,7 @@ public String getDataFromClient(ProjectConfFieldMapping projectConfig, URL url,
String responce = krb5Client.getResponse(request);
return responce;
} else {
return getDataFromServer(url, connectionOptional);
return getDataFromServer(url, connectionOptional, projectConfigId);
}
}

Expand All @@ -127,7 +134,7 @@ public String getDataFromClient(ProjectConfFieldMapping projectConfig, URL url,
* @throws IOException
* IOException
*/
public String getDataFromServer(URL url, Optional<Connection> connectionOptional) throws IOException {
public String getDataFromServer(URL url, Optional<Connection> connectionOptional, ObjectId projectConfigId) throws IOException {
HttpURLConnection request = (HttpURLConnection) url.openConnection();

String username = null;
Expand All @@ -154,6 +161,8 @@ public String getDataFromServer(URL url, Optional<Connection> connectionOptional
request.setRequestProperty("Authorization", "Basic " + encodeCredentialsToBase64(username, password)); // NOSONAR
}
request.connect();
// process the client error
processClientError(connectionOptional, request, projectConfigId);
StringBuilder sb = new StringBuilder();
try (InputStream in = (InputStream) request.getContent();
BufferedReader inReader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
Expand All @@ -174,6 +183,71 @@ public String getDataFromServer(URL url, Optional<Connection> connectionOptional
return sb.toString();
}

/**
* Method to process client error and update the connection broken flag
*
* @param connectionOptional
* connectionOptional
* @param request
* request
* @throws IOException
* throw IO Error
*/
private void processClientError(Optional<Connection> connectionOptional, HttpURLConnection request,
ObjectId basicProjectConfigId) throws IOException {
int responseCode = request.getResponseCode();
if (responseCode >= 400 && responseCode < 500) {
// Read error message from the server
String errorMessage = readErrorStream(request.getErrorStream());
if (responseCode == 404) {
ErrorDetail errorDetail = new ErrorDetail(responseCode, request.getURL().toString(), errorMessage,
determineImpactBasedOnUrl(request.getURL().toString()));
Optional<ProcessorExecutionTraceLog> existingTraceLog = processorExecutionTraceLogRepository
.findByProcessorNameAndBasicProjectConfigIdAndProgressStatsTrue(JiraConstants.JIRA,
basicProjectConfigId.toString());
existingTraceLog.ifPresent(traceLog -> {
List<ErrorDetail> errorDetailList = Optional.ofNullable(traceLog.getErrorDetailList())
.orElseGet(ArrayList::new);
errorDetailList.add(errorDetail);
traceLog.setErrorDetailList(errorDetailList);
processorExecutionTraceLogRepository.save(traceLog);
});
}
// flagging the connection flag w.r.t error code.
connectionOptional.ifPresent(connection -> {
String errMsg = ClientErrorMessageEnum.fromValue(responseCode).getReasonPhrase();
processorToolConnectionService.updateBreakingConnection(connection.getId(), errMsg);
});
log.error("Exception when reading from server {} - {}", responseCode, errorMessage);
// Throw exception for non-404 errors, as 404 indicates the resource mightn't exist
if (responseCode != 404) {
request.disconnect();
throw new IOException(String.format("Error: %d - %s", responseCode, errorMessage));
}
}
}

private String readErrorStream(InputStream errorStream) throws IOException {
StringBuilder response = new StringBuilder();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
}
return response.toString();
}

private String determineImpactBasedOnUrl(String url) {
if (url.contains("sprint")) {
return "Sprint KPI's";
} else if (url.contains("versions")) {
return "Release KPI's";
} else if (url.contains("epic")) {
return "Epic KPI's";
}
return ""; // Default or unknown impact
}
/**
*
* @param connectionOptional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public void setExecutionOngoingForProcessor(String processorName, String basicPr
processorExecutionTraceLog.setProgressStatusList(new ArrayList<>()); // clear the prev record
processorExecutionTraceLog.setErrorMessage(null); // Clear the error message
processorExecutionTraceLog.setFailureLog(null); // Clear the failure log message
processorExecutionTraceLog.setErrorDetailList(new ArrayList<>());
}
log.info("ProjectId {} for processor {} executionOngoing to {} ", basicProjectConfigId, processorName ,
executionOngoing);
Expand Down
Loading

0 comments on commit 6305db8

Please sign in to comment.