All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.solr.handler.admin.api.SnapshotBackupAPI Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.solr.handler.admin.api;

import static org.apache.solr.client.solrj.impl.BinaryResponseParser.BINARY_CONTENT_TYPE_V2;
import static org.apache.solr.handler.ReplicationHandler.ERR_STATUS;
import static org.apache.solr.security.PermissionNameProvider.Name.CORE_EDIT_PERM;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import jakarta.inject.Inject;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.function.Consumer;
import org.apache.solr.api.JerseyResource;
import org.apache.solr.client.api.model.SolrJerseyResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.annotation.JsonProperty;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.ReplicationHandler;
import org.apache.solr.handler.ReplicationHandler.ReplicationHandlerConfig;
import org.apache.solr.jersey.JacksonReflectMapWriter;
import org.apache.solr.jersey.PermissionName;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** V2 endpoint for Backup API used for User-Managed clusters and Single-Node Installation. */
@Path("/cores/{coreName}/replication/backups")
public class SnapshotBackupAPI extends JerseyResource {

  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
  private final SolrCore solrCore;
  private final ReplicationHandlerConfig replicationHandlerConfig;

  @Inject
  public SnapshotBackupAPI(SolrCore solrCore, ReplicationHandlerConfig replicationHandlerConfig) {
    this.solrCore = solrCore;
    this.replicationHandlerConfig = replicationHandlerConfig;
  }

  /**
   * This API (POST /api/cores/coreName/replication/backups {...}) is analogous to the v1
   * /solr/coreName/replication?command=backup
   */
  @POST
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, BINARY_CONTENT_TYPE_V2})
  @Operation(summary = "Backup command using ReplicationHandler")
  @PermissionName(CORE_EDIT_PERM)
  public BackupReplicationResponse createBackup(
      @RequestBody BackupReplicationRequestBody backupReplicationPayload) throws Exception {
    ensureRequiredRequestBodyProvided(backupReplicationPayload);
    ReplicationHandler replicationHandler =
        (ReplicationHandler) solrCore.getRequestHandler(ReplicationHandler.PATH);
    return doBackup(replicationHandler, backupReplicationPayload);
  }

  private BackupReplicationResponse doBackup(
      ReplicationHandler replicationHandler,
      BackupReplicationRequestBody backupReplicationPayload) {
    BackupReplicationResponse response = instantiateJerseyResponse(BackupReplicationResponse.class);
    int numberToKeep = backupReplicationPayload.numberToKeep;
    int numberBackupsToKeep = replicationHandlerConfig.getNumberBackupsToKeep();
    String location = backupReplicationPayload.location;
    String repoName = backupReplicationPayload.repository;
    String commitName = backupReplicationPayload.commitName;
    String name = backupReplicationPayload.name;
    Consumer> resultConsumer = result -> response.result = result;
    try {
      doSnapShoot(
          numberToKeep,
          numberBackupsToKeep,
          location,
          repoName,
          commitName,
          name,
          solrCore,
          resultConsumer);
      response.status = ReplicationHandler.OK_STATUS;
    } catch (SolrException e) {
      throw e;
    } catch (Exception e) {
      log.error("Exception while creating a snapshot", e);
      reportErrorOnResponse(
          response, "Error encountered while creating a snapshot: " + e.getMessage(), e);
    }
    return response;
  }

  /** Separate method helps with testing */
  protected void doSnapShoot(
      int numberToKeep,
      int numberBackupsToKeep,
      String location,
      String repoName,
      String commitName,
      String name,
      SolrCore solrCore,
      Consumer> resultConsumer)
      throws IOException {
    ReplicationHandler.doSnapShoot(
        numberToKeep,
        numberBackupsToKeep,
        location,
        repoName,
        commitName,
        name,
        solrCore,
        resultConsumer);
  }

  /* POJO for v2 endpoints request body. */
  public static class BackupReplicationRequestBody implements JacksonReflectMapWriter {

    public BackupReplicationRequestBody() {}

    public BackupReplicationRequestBody(
        String location, String name, int numberToKeep, String repository, String commitName) {
      this.location = location;
      this.name = name;
      this.numberToKeep = numberToKeep;
      this.repository = repository;
      this.commitName = commitName;
    }

    @Schema(description = "The path where the backup will be created")
    @JsonProperty
    public String location;

    @Schema(description = "The backup will be created in a directory called snapshot.")
    @JsonProperty
    public String name;

    @Schema(description = "The number of backups to keep.")
    @JsonProperty
    public int numberToKeep;

    @Schema(description = "The name of the repository to be used for e backup.")
    @JsonProperty
    public String repository;

    @Schema(
        description =
            "The name of the commit which was used while taking a snapshot using the CREATESNAPSHOT command.")
    @JsonProperty
    public String commitName;
  }

  /** Response for {@link SnapshotBackupAPI#createBackup(BackupReplicationRequestBody)}. */
  public static class BackupReplicationResponse extends SolrJerseyResponse {

    @JsonProperty("result")
    public NamedList result;

    @JsonProperty("status")
    public String status;

    @JsonProperty("message")
    public String message;

    @JsonProperty("exception")
    public Exception exception;

    public BackupReplicationResponse() {}
  }

  private static void reportErrorOnResponse(
      BackupReplicationResponse response, String message, Exception e) {
    response.status = ERR_STATUS;
    response.message = message;
    if (e != null) {
      response.exception = e;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy