@Test public void testConfigureAnalysis() throws IOException { String containerName = "myContainer"; _manager.initNetwork(containerName, null); Map<String, String> questionsToAdd = ImmutableMap.of("question1", "question1Content"); String analysisName = "analysis"; _manager.configureAnalysis( containerName, true, analysisName, questionsToAdd, Lists.newArrayList(), null); questionsToAdd = ImmutableMap.of("question2", "question2Content", "question3", "question3Content"); _manager.configureAnalysis( containerName, false, analysisName, questionsToAdd, Lists.newArrayList(), null); NetworkId networkId = _idManager.getNetworkId(containerName).get(); AnalysisId analysisId = _idManager.getAnalysisId(analysisName, networkId).get(); QuestionId q1Id = _idManager.getQuestionId("question1", networkId, analysisId).get(); QuestionId q2Id = _idManager.getQuestionId("question2", networkId, analysisId).get(); String actual = _storage.loadQuestion(networkId, q1Id, analysisId); assertThat(actual, equalTo("question1Content")); actual = _storage.loadQuestion(networkId, q2Id, analysisId); assertThat(actual, equalTo("question2Content")); List<String> questionsToDelete = ImmutableList.of(); _manager.configureAnalysis( containerName, false, analysisName, ImmutableMap.of(), questionsToDelete, null); assertTrue( _idManager.hasQuestionId("question1", networkId, analysisId) && _idManager.hasQuestionId("question2", networkId, analysisId) && _idManager.hasQuestionId("question3", networkId, analysisId)); questionsToDelete = ImmutableList.of("question1", "question2"); _manager.configureAnalysis( containerName, false, analysisName, ImmutableMap.of(), questionsToDelete, null); assertFalse(_idManager.hasQuestionId("question1", networkId, analysisId)); assertFalse(_idManager.hasQuestionId("question2", networkId, analysisId)); assertTrue(_idManager.hasQuestionId("question3", networkId, analysisId)); _thrown.expect(IllegalArgumentException.class); _thrown.expectMessage(equalTo("Question 'question1' does not exist for analysis 'analysis'")); questionsToDelete = ImmutableList.of("question1"); _manager.configureAnalysis( containerName, false, analysisName, ImmutableMap.of(), questionsToDelete, null); }
public void configureAnalysis( String network, boolean newAnalysis, String analysis, Map<String, String> questionsToAdd, List<String> questionsToDelete, @Nullable Boolean suggested) throws IOException { Optional<NetworkId> networkIdOpt = _idManager.getNetworkId(network); checkArgument(networkIdOpt.isPresent(), "Invalid network: %s", network); NetworkId networkId = networkIdOpt.get(); AnalysisId analysisId = null; Optional<AnalysisId> analysisIdOpt = _idManager.getAnalysisId(analysis, networkId); if (newAnalysis) { checkArgument( !analysisIdOpt.isPresent(), "Analysis %s for network %s already exists", analysis, network); checkArgument(questionsToDelete.isEmpty(), "Cannot delete questions from a new analysis"); analysisId = _idManager.generateAnalysisId(); } else { checkArgument( analysisIdOpt.isPresent(), "Analysis '%s' does not exist for network '%s'", analysis, network); analysisId = analysisIdOpt.get(); for (String qName : questionsToDelete) { if (!_idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format("Question '%s' does not exist for analysis '%s'", qName, analysis)); } } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); if (!questionsToDelete.contains(qName) && _idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format( "Question '%s' already exists for analysis '%s'", entry.getKey(), analysis)); } } } if (newAnalysis || suggested != null) { AnalysisMetadata metadata; if (newAnalysis) { metadata = new AnalysisMetadata(Instant.now(), (suggested != null) && suggested); } else if (!_storage.hasAnalysisMetadata(networkId, analysisId)) { metadata = new AnalysisMetadata(Instant.MIN, suggested); } else { try { metadata = AnalysisMetadataMgr.readMetadata(networkId, analysisId); metadata.setSuggested(suggested); } catch (IOException e) { throw new BatfishException( "Unable to read metadata file for analysis '" + analysis + "'", e); } } try { AnalysisMetadataMgr.writeMetadata(metadata, networkId, analysisId); } catch (IOException e) { throw new BatfishException("Could not write analysisMetadata", e); } } for (String qName : questionsToDelete) { _idManager.deleteQuestion(qName, networkId, analysisId); } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); String qText = entry.getValue(); QuestionId questionId = _idManager.generateQuestionId(); _storage.storeQuestion(qText, networkId, questionId, analysisId); _idManager.assignQuestion(qName, networkId, questionId, analysisId); } if (newAnalysis) { _idManager.assignAnalysis(analysis, networkId, analysisId); } }
WorkMgr extends AbstractCoordinator { public void configureAnalysis( String network, boolean newAnalysis, String analysis, Map<String, String> questionsToAdd, List<String> questionsToDelete, @Nullable Boolean suggested) throws IOException { Optional<NetworkId> networkIdOpt = _idManager.getNetworkId(network); checkArgument(networkIdOpt.isPresent(), "Invalid network: %s", network); NetworkId networkId = networkIdOpt.get(); AnalysisId analysisId = null; Optional<AnalysisId> analysisIdOpt = _idManager.getAnalysisId(analysis, networkId); if (newAnalysis) { checkArgument( !analysisIdOpt.isPresent(), "Analysis %s for network %s already exists", analysis, network); checkArgument(questionsToDelete.isEmpty(), "Cannot delete questions from a new analysis"); analysisId = _idManager.generateAnalysisId(); } else { checkArgument( analysisIdOpt.isPresent(), "Analysis '%s' does not exist for network '%s'", analysis, network); analysisId = analysisIdOpt.get(); for (String qName : questionsToDelete) { if (!_idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format("Question '%s' does not exist for analysis '%s'", qName, analysis)); } } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); if (!questionsToDelete.contains(qName) && _idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format( "Question '%s' already exists for analysis '%s'", entry.getKey(), analysis)); } } } if (newAnalysis || suggested != null) { AnalysisMetadata metadata; if (newAnalysis) { metadata = new AnalysisMetadata(Instant.now(), (suggested != null) && suggested); } else if (!_storage.hasAnalysisMetadata(networkId, analysisId)) { metadata = new AnalysisMetadata(Instant.MIN, suggested); } else { try { metadata = AnalysisMetadataMgr.readMetadata(networkId, analysisId); metadata.setSuggested(suggested); } catch (IOException e) { throw new BatfishException( "Unable to read metadata file for analysis '" + analysis + "'", e); } } try { AnalysisMetadataMgr.writeMetadata(metadata, networkId, analysisId); } catch (IOException e) { throw new BatfishException("Could not write analysisMetadata", e); } } for (String qName : questionsToDelete) { _idManager.deleteQuestion(qName, networkId, analysisId); } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); String qText = entry.getValue(); QuestionId questionId = _idManager.generateQuestionId(); _storage.storeQuestion(qText, networkId, questionId, analysisId); _idManager.assignQuestion(qName, networkId, questionId, analysisId); } if (newAnalysis) { _idManager.assignAnalysis(analysis, networkId, analysisId); } } }
WorkMgr extends AbstractCoordinator { public void configureAnalysis( String network, boolean newAnalysis, String analysis, Map<String, String> questionsToAdd, List<String> questionsToDelete, @Nullable Boolean suggested) throws IOException { Optional<NetworkId> networkIdOpt = _idManager.getNetworkId(network); checkArgument(networkIdOpt.isPresent(), "Invalid network: %s", network); NetworkId networkId = networkIdOpt.get(); AnalysisId analysisId = null; Optional<AnalysisId> analysisIdOpt = _idManager.getAnalysisId(analysis, networkId); if (newAnalysis) { checkArgument( !analysisIdOpt.isPresent(), "Analysis %s for network %s already exists", analysis, network); checkArgument(questionsToDelete.isEmpty(), "Cannot delete questions from a new analysis"); analysisId = _idManager.generateAnalysisId(); } else { checkArgument( analysisIdOpt.isPresent(), "Analysis '%s' does not exist for network '%s'", analysis, network); analysisId = analysisIdOpt.get(); for (String qName : questionsToDelete) { if (!_idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format("Question '%s' does not exist for analysis '%s'", qName, analysis)); } } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); if (!questionsToDelete.contains(qName) && _idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format( "Question '%s' already exists for analysis '%s'", entry.getKey(), analysis)); } } } if (newAnalysis || suggested != null) { AnalysisMetadata metadata; if (newAnalysis) { metadata = new AnalysisMetadata(Instant.now(), (suggested != null) && suggested); } else if (!_storage.hasAnalysisMetadata(networkId, analysisId)) { metadata = new AnalysisMetadata(Instant.MIN, suggested); } else { try { metadata = AnalysisMetadataMgr.readMetadata(networkId, analysisId); metadata.setSuggested(suggested); } catch (IOException e) { throw new BatfishException( "Unable to read metadata file for analysis '" + analysis + "'", e); } } try { AnalysisMetadataMgr.writeMetadata(metadata, networkId, analysisId); } catch (IOException e) { throw new BatfishException("Could not write analysisMetadata", e); } } for (String qName : questionsToDelete) { _idManager.deleteQuestion(qName, networkId, analysisId); } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); String qText = entry.getValue(); QuestionId questionId = _idManager.generateQuestionId(); _storage.storeQuestion(qText, networkId, questionId, analysisId); _idManager.assignQuestion(qName, networkId, questionId, analysisId); } if (newAnalysis) { _idManager.assignAnalysis(analysis, networkId, analysisId); } } WorkMgr(
      Settings settings,
      BatfishLogger logger,
      @Nonnull IdManager idManager,
      @Nonnull StorageProvider storage); }
WorkMgr extends AbstractCoordinator { public void configureAnalysis( String network, boolean newAnalysis, String analysis, Map<String, String> questionsToAdd, List<String> questionsToDelete, @Nullable Boolean suggested) throws IOException { Optional<NetworkId> networkIdOpt = _idManager.getNetworkId(network); checkArgument(networkIdOpt.isPresent(), "Invalid network: %s", network); NetworkId networkId = networkIdOpt.get(); AnalysisId analysisId = null; Optional<AnalysisId> analysisIdOpt = _idManager.getAnalysisId(analysis, networkId); if (newAnalysis) { checkArgument( !analysisIdOpt.isPresent(), "Analysis %s for network %s already exists", analysis, network); checkArgument(questionsToDelete.isEmpty(), "Cannot delete questions from a new analysis"); analysisId = _idManager.generateAnalysisId(); } else { checkArgument( analysisIdOpt.isPresent(), "Analysis '%s' does not exist for network '%s'", analysis, network); analysisId = analysisIdOpt.get(); for (String qName : questionsToDelete) { if (!_idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format("Question '%s' does not exist for analysis '%s'", qName, analysis)); } } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); if (!questionsToDelete.contains(qName) && _idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format( "Question '%s' already exists for analysis '%s'", entry.getKey(), analysis)); } } } if (newAnalysis || suggested != null) { AnalysisMetadata metadata; if (newAnalysis) { metadata = new AnalysisMetadata(Instant.now(), (suggested != null) && suggested); } else if (!_storage.hasAnalysisMetadata(networkId, analysisId)) { metadata = new AnalysisMetadata(Instant.MIN, suggested); } else { try { metadata = AnalysisMetadataMgr.readMetadata(networkId, analysisId); metadata.setSuggested(suggested); } catch (IOException e) { throw new BatfishException( "Unable to read metadata file for analysis '" + analysis + "'", e); } } try { AnalysisMetadataMgr.writeMetadata(metadata, networkId, analysisId); } catch (IOException e) { throw new BatfishException("Could not write analysisMetadata", e); } } for (String qName : questionsToDelete) { _idManager.deleteQuestion(qName, networkId, analysisId); } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); String qText = entry.getValue(); QuestionId questionId = _idManager.generateQuestionId(); _storage.storeQuestion(qText, networkId, questionId, analysisId); _idManager.assignQuestion(qName, networkId, questionId, analysisId); } if (newAnalysis) { _idManager.assignAnalysis(analysis, networkId, analysisId); } } WorkMgr(
      Settings settings,
      BatfishLogger logger,
      @Nonnull IdManager idManager,
      @Nonnull StorageProvider storage); @VisibleForTesting @Nonnull StorageProvider getStorage(); @Nullable List<AutocompleteSuggestion> autoComplete(
      String network,
      String snapshot,
      Variable.Type completionType,
      String query,
      int maxSuggestions); void configureAnalysis(
      String network,
      boolean newAnalysis,
      String analysis,
      Map<String, String> questionsToAdd,
      List<String> questionsToDelete,
      @Nullable Boolean suggested); boolean delAnalysis(@Nonnull String network, @Nonnull String analysis); boolean delNetwork(@Nonnull String network); boolean delSnapshot(@Nonnull String network, @Nonnull String snapshot); boolean delQuestion(
      @Nonnull String network, @Nonnull String question, @Nullable String analysis); @Nullable Answer getAnswer(
      String network,
      String snapshot,
      String question,
      @Nullable String referenceSnapshot,
      @Nullable String analysis); @Nonnull String getAnswerString(
      String network,
      String snapshot,
      String question,
      @Nullable String referenceSnapshot,
      @Nullable String analysis); List<QueuedWork> getCompletedWork(String networkName, String snapshotName); @Nonnull Map<String, String> getAnalysisAnswers(
      String network,
      String snapshot,
      String referenceSnapshot,
      String analysis,
      Set<String> analysisQuestions); @Nonnull Map<String, AnswerMetadata> getAnalysisAnswersMetadata(
      String network,
      String snapshot,
      String referenceSnapshot,
      String analysis,
      Set<String> analysisQuestions); @Nonnull AnswerMetadata getAnswerMetadata(
      @Nonnull String network,
      @Nonnull String snapshot,
      @Nonnull String question,
      @Nullable String referenceSnapshot,
      @Nullable String analysis); Container getContainer(String networkName); @Override BatfishLogger getLogger(); @Override Set<String> getNetworkNames(); @Nonnull Optional<String> getLatestSnapshot(String network); @Nullable Set<String> getNodes(String network, String snapshot); @Nullable Topology getPojoTopology(@Nonnull String network, @Nonnull String snapshot); ReferenceLibrary getReferenceLibrary(String network); JSONObject getStatusJson(); boolean checkSnapshotExists(String network, String snapshot); boolean checkQuestionExists(String network, String question, @Nullable String analysis); @Nullable String getQuestion(String network, String question, @Nullable String analysis); QueuedWork getMatchingWork(WorkItem workItem, QueueType qType); QueuedWork getWork(UUID workItemId); @Nullable String getWorkLog(String networkName, String snapshotName, String workId); @Nullable String getWorkJson(String networkName, String snapshotName, String workId); String initNetwork(@Nullable String network, @Nullable String networkPrefix); @Override void initSnapshot(
      String networkName,
      String snapshotName,
      Path srcDir,
      boolean autoAnalyze,
      Instant creationTime); void initSnapshot(
      String networkName,
      String snapshotName,
      Path srcDir,
      boolean autoAnalyze,
      Instant creationTime,
      @Nullable SnapshotId parentSnapshotId); void forkSnapshot(String networkName, ForkSnapshotBean forkSnapshotBean); @Nullable SortedSet<String> listAnalyses(String network, AnalysisType analysisType); @Nullable SortedSet<String> listAnalysisQuestions(String network, String analysis); SortedSet<String> listNetworks(String apiKey); List<Container> getContainers(@Nullable String apiKey); List<QueuedWork> listIncompleteWork(
      String network, @Nullable String snapshot, @Nullable WorkType workType); @Nullable SortedSet<String> listQuestions(String network, boolean verbose); @Nullable List<String> listSnapshots(@Nonnull String network); @Nullable List<SnapshotMetadataEntry> listSnapshotsWithMetadata(@Nonnull String network); void putReferenceLibrary(ReferenceLibrary referenceLibrary, String network); boolean queueWork(WorkItem workItem); void startWorkManager(); boolean uploadQuestion(String network, String question, String questionJson); void uploadSnapshot(
      String networkName, String snapshotName, InputStream fileStream, boolean autoAnalyze); boolean checkNetworkExists(String networkName); Map<String, Answer> processAnalysisAnswers(
      Map<String, String> rawAnswers, Map<String, AnswerRowsOptions> answersRowsOptions); Answer filterAnswer(Answer rawAnswer, AnswerRowsOptions options); @VisibleForTesting IdManager getIdManager(); @VisibleForTesting SnapshotMetadataMgr getSnapshotMetadataManager(); @Nullable SnapshotMetadata getSnapshotMetadata(String network, String snapshot); void tryPromoteSnapshotNodeRoles(
      @Nonnull NetworkId networkId, @Nonnull SnapshotId snapshotId); @Nullable NodeRolesData getNetworkNodeRoles(@Nonnull String network); @Nullable NodeRolesData getSnapshotNodeRoles(
      @Nonnull String network, @Nonnull String snapshot); @MustBeClosed @Nullable InputStream getNetworkObject(@Nonnull String network, @Nonnull String key); boolean putNetworkObject(
      @Nonnull InputStream inputStream, @Nonnull String network, @Nonnull String key); boolean deleteNetworkObject(@Nonnull String network, @Nonnull String key); @MustBeClosed @Nullable InputStream getSnapshotObject(
      @Nonnull String network, @Nonnull String snapshot, @Nonnull String key); boolean putSnapshotExtendedObject(
      @Nonnull InputStream inputStream,
      @Nonnull String network,
      @Nonnull String snapshot,
      @Nonnull String key); boolean deleteSnapshotObject(
      @Nonnull String network, @Nonnull String snapshot, @Nonnull String key); @MustBeClosed InputStream getSnapshotInputObject(String network, String snapshot, String key); @Nullable List<StoredObjectMetadata> getSnapshotInputObjectsMetadata(String network, String snapshot); @Nullable List<StoredObjectMetadata> getSnapshotExtendedObjectsMetadata(
      String network, String snapshot); @Nullable org.batfish.datamodel.Topology getTopology(String network, String snapshot); boolean putNetworkNodeRoles(@Nonnull NodeRolesData nodeRolesData, @Nonnull String network); @Nullable InputValidationNotes validateInput(
      String network, String snapshot, Variable.Type varType, String query); }
WorkMgr extends AbstractCoordinator { public void configureAnalysis( String network, boolean newAnalysis, String analysis, Map<String, String> questionsToAdd, List<String> questionsToDelete, @Nullable Boolean suggested) throws IOException { Optional<NetworkId> networkIdOpt = _idManager.getNetworkId(network); checkArgument(networkIdOpt.isPresent(), "Invalid network: %s", network); NetworkId networkId = networkIdOpt.get(); AnalysisId analysisId = null; Optional<AnalysisId> analysisIdOpt = _idManager.getAnalysisId(analysis, networkId); if (newAnalysis) { checkArgument( !analysisIdOpt.isPresent(), "Analysis %s for network %s already exists", analysis, network); checkArgument(questionsToDelete.isEmpty(), "Cannot delete questions from a new analysis"); analysisId = _idManager.generateAnalysisId(); } else { checkArgument( analysisIdOpt.isPresent(), "Analysis '%s' does not exist for network '%s'", analysis, network); analysisId = analysisIdOpt.get(); for (String qName : questionsToDelete) { if (!_idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format("Question '%s' does not exist for analysis '%s'", qName, analysis)); } } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); if (!questionsToDelete.contains(qName) && _idManager.hasQuestionId(qName, networkId, analysisId)) { throw new IllegalArgumentException( String.format( "Question '%s' already exists for analysis '%s'", entry.getKey(), analysis)); } } } if (newAnalysis || suggested != null) { AnalysisMetadata metadata; if (newAnalysis) { metadata = new AnalysisMetadata(Instant.now(), (suggested != null) && suggested); } else if (!_storage.hasAnalysisMetadata(networkId, analysisId)) { metadata = new AnalysisMetadata(Instant.MIN, suggested); } else { try { metadata = AnalysisMetadataMgr.readMetadata(networkId, analysisId); metadata.setSuggested(suggested); } catch (IOException e) { throw new BatfishException( "Unable to read metadata file for analysis '" + analysis + "'", e); } } try { AnalysisMetadataMgr.writeMetadata(metadata, networkId, analysisId); } catch (IOException e) { throw new BatfishException("Could not write analysisMetadata", e); } } for (String qName : questionsToDelete) { _idManager.deleteQuestion(qName, networkId, analysisId); } for (Entry<String, String> entry : questionsToAdd.entrySet()) { String qName = entry.getKey(); String qText = entry.getValue(); QuestionId questionId = _idManager.generateQuestionId(); _storage.storeQuestion(qText, networkId, questionId, analysisId); _idManager.assignQuestion(qName, networkId, questionId, analysisId); } if (newAnalysis) { _idManager.assignAnalysis(analysis, networkId, analysisId); } } WorkMgr(
      Settings settings,
      BatfishLogger logger,
      @Nonnull IdManager idManager,
      @Nonnull StorageProvider storage); @VisibleForTesting @Nonnull StorageProvider getStorage(); @Nullable List<AutocompleteSuggestion> autoComplete(
      String network,
      String snapshot,
      Variable.Type completionType,
      String query,
      int maxSuggestions); void configureAnalysis(
      String network,
      boolean newAnalysis,
      String analysis,
      Map<String, String> questionsToAdd,
      List<String> questionsToDelete,
      @Nullable Boolean suggested); boolean delAnalysis(@Nonnull String network, @Nonnull String analysis); boolean delNetwork(@Nonnull String network); boolean delSnapshot(@Nonnull String network, @Nonnull String snapshot); boolean delQuestion(
      @Nonnull String network, @Nonnull String question, @Nullable String analysis); @Nullable Answer getAnswer(
      String network,
      String snapshot,
      String question,
      @Nullable String referenceSnapshot,
      @Nullable String analysis); @Nonnull String getAnswerString(
      String network,
      String snapshot,
      String question,
      @Nullable String referenceSnapshot,
      @Nullable String analysis); List<QueuedWork> getCompletedWork(String networkName, String snapshotName); @Nonnull Map<String, String> getAnalysisAnswers(
      String network,
      String snapshot,
      String referenceSnapshot,
      String analysis,
      Set<String> analysisQuestions); @Nonnull Map<String, AnswerMetadata> getAnalysisAnswersMetadata(
      String network,
      String snapshot,
      String referenceSnapshot,
      String analysis,
      Set<String> analysisQuestions); @Nonnull AnswerMetadata getAnswerMetadata(
      @Nonnull String network,
      @Nonnull String snapshot,
      @Nonnull String question,
      @Nullable String referenceSnapshot,
      @Nullable String analysis); Container getContainer(String networkName); @Override BatfishLogger getLogger(); @Override Set<String> getNetworkNames(); @Nonnull Optional<String> getLatestSnapshot(String network); @Nullable Set<String> getNodes(String network, String snapshot); @Nullable Topology getPojoTopology(@Nonnull String network, @Nonnull String snapshot); ReferenceLibrary getReferenceLibrary(String network); JSONObject getStatusJson(); boolean checkSnapshotExists(String network, String snapshot); boolean checkQuestionExists(String network, String question, @Nullable String analysis); @Nullable String getQuestion(String network, String question, @Nullable String analysis); QueuedWork getMatchingWork(WorkItem workItem, QueueType qType); QueuedWork getWork(UUID workItemId); @Nullable String getWorkLog(String networkName, String snapshotName, String workId); @Nullable String getWorkJson(String networkName, String snapshotName, String workId); String initNetwork(@Nullable String network, @Nullable String networkPrefix); @Override void initSnapshot(
      String networkName,
      String snapshotName,
      Path srcDir,
      boolean autoAnalyze,
      Instant creationTime); void initSnapshot(
      String networkName,
      String snapshotName,
      Path srcDir,
      boolean autoAnalyze,
      Instant creationTime,
      @Nullable SnapshotId parentSnapshotId); void forkSnapshot(String networkName, ForkSnapshotBean forkSnapshotBean); @Nullable SortedSet<String> listAnalyses(String network, AnalysisType analysisType); @Nullable SortedSet<String> listAnalysisQuestions(String network, String analysis); SortedSet<String> listNetworks(String apiKey); List<Container> getContainers(@Nullable String apiKey); List<QueuedWork> listIncompleteWork(
      String network, @Nullable String snapshot, @Nullable WorkType workType); @Nullable SortedSet<String> listQuestions(String network, boolean verbose); @Nullable List<String> listSnapshots(@Nonnull String network); @Nullable List<SnapshotMetadataEntry> listSnapshotsWithMetadata(@Nonnull String network); void putReferenceLibrary(ReferenceLibrary referenceLibrary, String network); boolean queueWork(WorkItem workItem); void startWorkManager(); boolean uploadQuestion(String network, String question, String questionJson); void uploadSnapshot(
      String networkName, String snapshotName, InputStream fileStream, boolean autoAnalyze); boolean checkNetworkExists(String networkName); Map<String, Answer> processAnalysisAnswers(
      Map<String, String> rawAnswers, Map<String, AnswerRowsOptions> answersRowsOptions); Answer filterAnswer(Answer rawAnswer, AnswerRowsOptions options); @VisibleForTesting IdManager getIdManager(); @VisibleForTesting SnapshotMetadataMgr getSnapshotMetadataManager(); @Nullable SnapshotMetadata getSnapshotMetadata(String network, String snapshot); void tryPromoteSnapshotNodeRoles(
      @Nonnull NetworkId networkId, @Nonnull SnapshotId snapshotId); @Nullable NodeRolesData getNetworkNodeRoles(@Nonnull String network); @Nullable NodeRolesData getSnapshotNodeRoles(
      @Nonnull String network, @Nonnull String snapshot); @MustBeClosed @Nullable InputStream getNetworkObject(@Nonnull String network, @Nonnull String key); boolean putNetworkObject(
      @Nonnull InputStream inputStream, @Nonnull String network, @Nonnull String key); boolean deleteNetworkObject(@Nonnull String network, @Nonnull String key); @MustBeClosed @Nullable InputStream getSnapshotObject(
      @Nonnull String network, @Nonnull String snapshot, @Nonnull String key); boolean putSnapshotExtendedObject(
      @Nonnull InputStream inputStream,
      @Nonnull String network,
      @Nonnull String snapshot,
      @Nonnull String key); boolean deleteSnapshotObject(
      @Nonnull String network, @Nonnull String snapshot, @Nonnull String key); @MustBeClosed InputStream getSnapshotInputObject(String network, String snapshot, String key); @Nullable List<StoredObjectMetadata> getSnapshotInputObjectsMetadata(String network, String snapshot); @Nullable List<StoredObjectMetadata> getSnapshotExtendedObjectsMetadata(
      String network, String snapshot); @Nullable org.batfish.datamodel.Topology getTopology(String network, String snapshot); boolean putNetworkNodeRoles(@Nonnull NodeRolesData nodeRolesData, @Nonnull String network); @Nullable InputValidationNotes validateInput(
      String network, String snapshot, Variable.Type varType, String query);  }