Commit f68c3f5f authored by Christos Tranoris's avatar Christos Tranoris
Browse files

Merge branch 'develop' into 'main'

Pull latest changes from remote before writing

See merge request !2
parents 0018f884 c33a65a7
Loading
Loading
Loading
Loading
+67 −7
Original line number Diff line number Diff line
@@ -104,7 +104,18 @@ public class ResourceRepoService {
        // Step 1: Validate Custom Resource against CRD schema
        validateCustomResource(cr, messages, operationType);

        // Step 2: Write Custom Resource to Git repository (filename: name-resourceid.yaml)
        // Step 2: Pull latest changes from remote before writing
        try {
          gitAdapter.pull();
          log.info("Pulled latest changes from remote before {}", operationType);
        } catch (Exception pullException) {
          log.warn("Failed to pull latest changes before {}: {}. Proceeding anyway.",
                   operationType, pullException.getMessage());
          messages.append(String.format("Warning: Pull failed (%s), proceeding with local state. ",
                   pullException.getMessage()));
        }

        // Step 3: Write Custom Resource to Git repository (filename: name-resourceid.yaml)
        crFilePath = gitAdapter.writeCustomResource(cr, resourceid);

        String s = String.format("Custom Resource %s in Git - Path: %s",
@@ -112,7 +123,7 @@ public class ResourceRepoService {
        messages.append(s);
        log.info(s);

        // Step 3: Commit changes
        // Step 4: Commit changes
        String commitMessage = String.format("[%s] %s %s-%s",
                operationType, cr.getKind(), cr.getMetadata().getName(), resourceid);
        String commitId = gitAdapter.commit(commitMessage, resourceid);
@@ -121,12 +132,10 @@ public class ResourceRepoService {
        messages.append(s);
        log.info(s);

        // Step 4: Push to remote
        gitAdapter.push();
        log.info("Changes pushed to remote");
        messages.append(" Pushed to remote.");
        // Step 5: Push to remote (with retry on conflict)
        pushWithRetry(messages);

        // Step 5: Handle reconciliation
        // Step 6: Handle reconciliation
        handleReconciliation(operationType, resourceid, cr, crFilePath, messages);

        s = String.format(" %s operation completed successfully", operationType);
@@ -227,6 +236,57 @@ public class ResourceRepoService {
    }
  }

  /**
   * Push to remote with retry on conflict.
   * If push fails due to non-fast-forward, pulls latest changes and retries.
   */
  private void pushWithRetry(StringBuilder messages) throws IOException {
    int maxRetries = 3;
    int retryCount = 0;

    while (retryCount < maxRetries) {
      try {
        gitAdapter.push();
        log.info("Changes pushed to remote");
        messages.append(" Pushed to remote.");
        return; // Success, exit loop
      } catch (Exception pushException) {
        retryCount++;
        String errorMsg = pushException.getMessage() != null ? pushException.getMessage() : "Unknown error";

        // Check if it's a non-fast-forward error (conflict)
        if (errorMsg.contains("non-fast-forward") || errorMsg.contains("rejected") ||
            errorMsg.contains("failed to push") || errorMsg.contains("fetch first")) {

          if (retryCount < maxRetries) {
            log.warn("Push failed (attempt {}/{}): {}. Pulling and retrying...",
                     retryCount, maxRetries, errorMsg);
            messages.append(String.format(" Push conflict (attempt %d), pulling and retrying.", retryCount));

            try {
              // Pull latest changes (this should merge/rebase)
              gitAdapter.pull();
              log.info("Pulled latest changes after push conflict");
            } catch (Exception pullEx) {
              log.error("Failed to pull after push conflict: {}", pullEx.getMessage());
              messages.append(String.format(" Pull after conflict failed: %s.", pullEx.getMessage()));
              throw new IOException("Push conflict and unable to resolve: " + pullEx.getMessage(), pullEx);
            }
          } else {
            log.error("Push failed after {} retries: {}", maxRetries, errorMsg);
            messages.append(String.format(" Push failed after %d retries: %s.", maxRetries, errorMsg));
            throw new IOException("Push failed after " + maxRetries + " retries: " + errorMsg, pushException);
          }
        } else {
          // Not a conflict error, fail immediately
          log.error("Push failed with error: {}", errorMsg);
          messages.append(String.format(" Push failed: %s.", errorMsg));
          throw new IOException("Push failed: " + errorMsg, pushException);
        }
      }
    }
  }
  
  public Resource deleteResource( Map<String, Object> headers, ResourceUpdate r) {
    String resourceid = "";

+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ producer:
  status-watcher:
    poll-interval-ms: ${PRODUCER_STATUS_WATCHER_POLL_INTERVAL:10000}
    timeout-ms: ${PRODUCER_STATUS_WATCHER_TIMEOUT:30000}
    persistence-path: ${PRODUCER_STATUS_WATCHER_PERSISTENCE_PATH:}
    persistence-path: ${PRODUCER_STATUS_WATCHER_PERSISTENCE_PATH:/tmp/.}
    default-resource-status-type: ${PRODUCER_STATUS_WATCHER_DEFAULT_RESOURCE_STATUS_TYPE:UNKNOWN}
    default-operational-state-type: ${PRODUCER_STATUS_WATCHER_DEFAULT_OPERATIONAL_STATE_TYPE:DISABLE}
    status-mappings: