package org.yamcs.web.rest.archive; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import java.nio.CharBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.concurrent.CompletableFuture; import org.rocksdb.RocksDBException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yamcs.api.MediaType; import org.yamcs.cli.Backup; import org.yamcs.security.Privilege; import org.yamcs.web.BadRequestException; import org.yamcs.web.ForbiddenException; import org.yamcs.web.HttpException; import org.yamcs.web.InternalServerErrorException; import org.yamcs.web.rest.RestHandler; import org.yamcs.web.rest.RestRequest; import org.yamcs.web.rest.Route; import org.yamcs.yarch.rocksdb.RDBFactory; import org.yamcs.yarch.rocksdb.YRDB; public class RocksDbMaintenanceRestHandler extends RestHandler { private static final Logger log = LoggerFactory.getLogger(RocksDbMaintenanceRestHandler.class); @Route(path = "/api/archive/:instance/rocksdb/properties/:dbpath*", method = "GET") public void getProperty(RestRequest req) throws HttpException { checkPrivileges(req); String instance = verifyInstance(req, req.getRouteParam("instance")); String dbpath = req.getRouteParam("dbpath"); RDBFactory rdbFactory = RDBFactory.getInstance(instance); if(rdbFactory==null) { throw new BadRequestException("No Rocksdb for instance "+instance); } YRDB yrdb = rdbFactory.getOpenRdb(dbpath); if(yrdb == null) { yrdb = rdbFactory.getOpenRdb("/"+dbpath); } if(yrdb == null) { throw new BadRequestException("No Open database "+dbpath+" for instance "+instance); } try { String s = yrdb.getProperites(); CharBuffer props = CharBuffer.wrap(s); ByteBuf buf = ByteBufUtil.encodeString(req.getChannelHandlerContext().alloc(), props, StandardCharsets.UTF_8); completeOK(req, MediaType.PLAIN_TEXT, buf); } catch (RocksDBException e) { log.error("Error when getting database properties",e); completeWithError(req, new InternalServerErrorException(e)); } finally { rdbFactory.dispose(yrdb); } } @Route(path = "/api/archive/:instance/rocksdb/list", method = "GET") public void listOpenDbs(RestRequest req) throws HttpException { checkPrivileges(req); String instance = verifyInstance(req, req.getRouteParam("instance")); RDBFactory rdbFactory = RDBFactory.getInstance(instance); if(rdbFactory==null) { throw new BadRequestException("No Rocksdb for instance "+instance); } List<String> list =rdbFactory.getOpenDbPaths(); StringBuilder sb = new StringBuilder(); for(String s:list) { sb.append(s).append("\n"); } CharBuffer props = CharBuffer.wrap(sb.toString()); ByteBuf buf = ByteBufUtil.encodeString(req.getChannelHandlerContext().alloc(), props, StandardCharsets.UTF_8); completeOK(req, MediaType.PLAIN_TEXT, buf); } @Route(path = "/api/archive/:instance/rocksdb/backup/:dbpath*", method = "POST") public void doBackup(RestRequest req) throws HttpException { checkPrivileges(req); String instance = verifyInstance(req, req.getRouteParam("instance")); String dbdir = "/"+req.getRouteParam("dbpath"); String backupDir = req.getQueryParameter("backupDir"); if(backupDir==null) throw new BadRequestException("No backup directory specified"); try { Backup.verifyBackupDirectory(backupDir, false); } catch (Exception e1) { throw new BadRequestException(e1.getMessage()); } Path dbpath = FileSystems.getDefault().getPath(dbdir); if(!Files.exists(dbpath)) throw new BadRequestException("Database '"+dbpath+"' does not exist"); RDBFactory rdbFactory = RDBFactory.getInstance(instance); if(rdbFactory==null) { throw new BadRequestException("No Rocksdb for instance "+instance); } CompletableFuture<Void> cf = rdbFactory.doBackup(dbdir, backupDir); cf.whenComplete((r, e) -> { if(e!=null) { completeWithError(req, new InternalServerErrorException(e)); } else { completeOK(req); } }); } private void checkPrivileges(RestRequest req) throws HttpException { if(!Privilege.getInstance().hasPrivilege1(req.getAuthToken(), Privilege.SystemPrivilege.MayControlArchiving)) { throw new ForbiddenException("No privilege for this operation"); } } }