ARTIFACTORY: How to resolve JFrog CLI downloading files that failed from the virtual repository that contains multiple smart repositories
Introduction When utilizing the JFrog CLI to retrieve files from a virtual repository that encompasses several smart remote repositories, one might experience issues such as file download failures or incomplete downloads. Here is the example that may be encountered:
-
Create several local repositories with Generic type on Artifactory node 1 and upload the test files separately.
- Create several smart remote repositories on Artifactory node 2 that proxy local repositories on Artifactory node 1
- Create a virtual repository with Generic type named test-generic-virtual on Artifactory node 2 which includes all the above smart remote repositories
- When using the JFrog CLI to download files from the virtual repository test-generic-virtual, we may encounter failure or incomplete file downloads.
- In this example, the test-generic-virtual repository contains seven smart remote repositories, smart remote repository proxy generic local repository at Artifactory node 1.
- When downloading all the files in the local repository at Artifactory node 1 through the test-generic-virtual, we may encounter an incomplete download.
- There are seven files on the Artifactory node 1, but the JFrog CLI only downloads five files.
Root Cause We can analyze the reasons for the above phenomenon from the JFrog CLI logs and Artifactory logs.
-
The JFrog CLI debug log:[Debug] Usage Report: Sending info... [Debug] Sending HTTP GET request to: http://<art_node2>:8082/artifactory/api/system/version [Debug] Sending HTTP GET request to: http://<art_node2>:8082/artifactory/api/system/version [Debug] Artifactory response: 200 OK [Debug] JFrog Artifactory version is: 7.98.11 [Debug] Sending HTTP POST request to: http://<art_node2>:8082/artifactory/api/system/usage [Debug] Artifactory response: 200 OK [Debug] JFrog Artifactory version is: 7.98.11 [Debug] Searching Artifactory using AQL query: items.find({"$or":[{"$and":[{"repo":"test-generic-virtual","path":{"$match":"*"},"name":{"$match":"*"}}]}]}).include("name","repo","path","actual_md5","actual_sha1","sha256","size","type","modified","created","property").transitive() [Debug] Sending HTTP POST request to: http://<art_node2>:8082/artifactory/api/search/aql [Debug] Artifactory response: 200 OK [Debug] Streaming data to file... [Debug] Finished streaming data successfully. [Info] [Thread 0] Downloading "test-generic-remote-2/test2.file" to "test2.file" ...... ...... [Debug] [Thread 2] Artifactory response: 200 OK [Debug] [Thread 0] Artifactory response: 200 OK [Debug] Downloaded 5 artifacts.- We can get that the JFrog CLI sends an AQL query request to the test-generic-virtual repository before downloading the files
- Artifactory node 2 Artifactory logs:
# The AQL request only return five repo’s artifacts to download. artifactory-request.log:2247:2024-12-27T08:31:32.885Z|7c5824a5cf507379|198.19.249.3|admin|POST|/api/search/aql|200|233|2106|203|jfrog-cli-go/2.71.0 artifactory-request.log:2248:2024-12-27T08:31:32.967Z|7c5824a5cf507379|198.19.249.3|admin|GET|/test-generic-remote-3/test3.file|200|-1|2|28|jfrog-cli-go/2.71.0 artifactory-request.log:2249:2024-12-27T08:31:32.972Z|7c5824a5cf507379|198.19.249.3|admin|GET|/test-generic-remote-5/test5.file|200|-1|2|33|jfrog-cli-go/2.71.0 artifactory-request.log:2250:2024-12-27T08:31:32.996Z|7c5824a5cf507379|198.19.249.3|admin|GET|/test-generic-remote-6/test6.file|200|-1|2|25|jfrog-cli-go/2.71.0 artifactory-request.log:2251:2024-12-27T08:31:33.000Z|7c5824a5cf507379|198.19.249.3|admin|GET|/test-generic-remote-7/test7.file|200|-1|2|23|jfrog-cli-go/2.71.0 artifactory-request.log:2252:2024-12-27T08:31:33.002Z|7c5824a5cf507379|198.19.249.3|admin|GET|/test-generic-remote-2/test2.file|200|-1|2|63|jfrog-cli-go/2.71.0 # only Download five Artifacts from proxy repo artifactory-request-out.log:96:2024-12-27T08:31:32.842Z|7c5824a5cf507379|test-generic-remote-7|admin|GET|http://<art_node1>:8082/artifactory/test-generic-local-7/|200|0|0|156 artifactory-request-out.log:97:2024-12-27T08:31:32.847Z|7c5824a5cf507379|test-generic-remote-7|admin|GET|http://<art_node1>:8082/artifactory/test-generic-local-7/|200|0|0|4 artifactory-request-out.log:98:2024-12-27T08:31:32.854Z|7c5824a5cf507379|test-generic-remote-6|admin|GET|http://<art_node1>:8082/artifactory/test-generic-local-6/|200|0|0|6 artifactory-request-out.log:99:2024-12-27T08:31:32.861Z|7c5824a5cf507379|test-generic-remote-3|admin|GET|http://<art_node1>:8082/artifactory/test-generic-local-3/|200|0|0|7 artifactory-request-out.log:100:2024-12-27T08:31:32.868Z|7c5824a5cf507379|test-generic-remote-5|admin|GET|http://<art_node1>:8082/artifactory/test-generic-local-5/|200|0|0|7 artifactory-request-out.log:101:2024-12-27T08:31:32.878Z|7c5824a5cf507379|test-generic-remote-2|admin|POST|http://<art_node1>:8082/artifactory/api/search/aql|200|242|0|9 artifactory-request-out.log:102:2024-12-27T08:31:32.880Z|7c5824a5cf507379|test-generic-remote-3|admin|POST|http://<art_node1>:8082/artifactory/api/search/aql|200|242|0|11 artifactory-request-out.log:103:2024-12-27T08:31:32.882Z|7c5824a5cf507379|test-generic-remote-6|admin|POST|http://<art_node1>:8082/artifactory/api/search/aql|200|242|0|13 artifactory-request-out.log:104:2024-12-27T08:31:32.883Z|7c5824a5cf507379|test-generic-remote-7|admin|POST|http://<art_node1>:8082/artifactory/api/search/aql|200|242|0|14 artifactory-request-out.log:105:2024-12-27T08:31:32.883Z|7c5824a5cf507379|test-generic-remote-5|admin|POST|http://<art_node1>:8082/artifactory/api/search/aql|200|242|0|12 artifactory-request-out.log:106:2024-12-27T08:31:32.945Z|7c5824a5cf507379|test-generic-remote-5|admin|HEAD|http://<art_node1>:8082/artifactory/test-generic-local-5/test5.file|200|0|2|4 artifactory-request-out.log:107:2024-12-27T08:31:32.945Z|7c5824a5cf507379|test-generic-remote-3|admin|HEAD|http://<art_node1>:8082/artifactory/test-generic-local-3/test3.file|200|0|2|3 artifactory-request-out.log:108:2024-12-27T08:31:32.951Z|7c5824a5cf507379|test-generic-remote-2|admin|HEAD|http://<art_node1>:8082/artifactory/test-generic-local-2/test2.file|200|0|2|10 artifactory-request-out.log:109:2024-12-27T08:31:32.976Z|7c5824a5cf507379|test-generic-remote-2|admin|GET|http://<art_node1>:8082/artifactory/test-generic-local-2/test2.file:properties|302|0|0|3 artifactory-request-out.log:110:2024-12-27T08:31:32.979Z|7c5824a5cf507379|test-generic-remote-6|admin|HEAD|http://<art_node1>:8082/artifactory/test-generic-local-6/test6.file|200|0|2|6 artifactory-request-out.log:111:2024-12-27T08:31:32.984Z|7c5824a5cf507379|test-generic-remote-7|admin|HEAD|http://<art_node1>:8082/artifactory/test-generic-local-7/test7.file|200|0|2|5 artifactory-request-out.log:112:2024-12-27T08:31:32.984Z|7c5824a5cf507379|test-generic-remote-2|admin|GET|/artifactory/api/storage/test-generic-local-2/test2.file?propertiesXml|404|0|0|4
- We can see from the Artifactory node 2 logs, the test-generic-virtual only sent AQL queries to 5 of the local repositories, resulting in incomplete files and downloads.
Resolution The Artifactory AQL API facilitates a transitive search capability, enabling the querying of both cached and non-cached items. However, when conducting an AQL search against a virtual repository, the scope is restricted to the top five remote repositories that it aggregates. This limitation is in place to ensure optimal performance. You can adjust this limit by adding a system property to the $JFROG_HOME/artifactory/etc/artifactory/artifactory.system.properties file to set a new limit, for example 10.
artifactory.aql.transitive.remote.repos.limit=10
Restart the Artifactory node so the configuration takes effect.