Skip to content

Commit 9d45211

Browse files
authored
feat: add logic to not download layers if already exists localy (#2056)
1 parent 261410d commit 9d45211

File tree

3 files changed

+148
-22
lines changed

3 files changed

+148
-22
lines changed

agent-control/src/package/manager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use oci_client::Reference;
66
use std::path::PathBuf;
77

88
/// Information required to reference and install a package
9-
#[derive(Debug)]
9+
#[derive(Debug, Clone)]
1010
pub struct PackageData {
1111
pub id: String, // same type as the packages map on an agent type definition
1212
pub package_type: PackageType,

agent-control/src/package/oci/package_manager.rs

Lines changed: 94 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,19 @@ where
225225
&package_data.id,
226226
&package_data.oci_reference,
227227
)?;
228+
229+
if package_path.exists() {
230+
debug!(
231+
"Package already installed at {}. Skipping download and extraction.",
232+
package_path.display()
233+
);
234+
235+
return Ok(InstalledPackageData {
236+
id: package_data.id,
237+
installation_path: package_path,
238+
});
239+
}
240+
228241
let temp_package_path = get_temp_package_path(
229242
&self.remote_dir,
230243
agent_id,
@@ -372,9 +385,12 @@ mod tests {
372385
let mut directory_manager = MockDirectoryManager::new();
373386

374387
let agent_id = AgentID::try_from("agent-id").unwrap();
375-
let root_dir = PathBuf::from("/tmp/base");
388+
389+
let temp_dir = tempdir().unwrap();
390+
let remote_dir = temp_dir.path().to_path_buf();
391+
376392
let download_dir = get_temp_package_path(
377-
&root_dir,
393+
&remote_dir,
378394
&agent_id,
379395
&TEST_PACKAGE_ID.to_string(),
380396
&test_reference(),
@@ -396,7 +412,7 @@ mod tests {
396412
let pm = OCIPackageManager {
397413
downloader,
398414
directory_manager,
399-
remote_dir: PathBuf::from("/tmp/base"),
415+
remote_dir,
400416
};
401417
let package_data = PackageData {
402418
id: TEST_PACKAGE_ID.to_string(),
@@ -414,9 +430,12 @@ mod tests {
414430
let mut directory_manager = MockDirectoryManager::new();
415431

416432
let agent_id = AgentID::try_from("agent-id").unwrap();
417-
let root_dir = PathBuf::from("/tmp/base");
433+
434+
let temp_dir = tempdir().unwrap();
435+
let remote_dir = temp_dir.path().to_path_buf();
436+
418437
let download_dir = get_temp_package_path(
419-
&root_dir,
438+
&remote_dir,
420439
&agent_id,
421440
&TEST_PACKAGE_ID.to_string(),
422441
&test_reference(),
@@ -448,7 +467,7 @@ mod tests {
448467
let pm = OCIPackageManager {
449468
downloader,
450469
directory_manager,
451-
remote_dir: PathBuf::from("/tmp/base"),
470+
remote_dir,
452471
};
453472
let package_data = PackageData {
454473
id: TEST_PACKAGE_ID.to_string(),
@@ -466,9 +485,12 @@ mod tests {
466485
let mut directory_manager = MockDirectoryManager::new();
467486

468487
let agent_id = AgentID::try_from("agent-id").unwrap();
469-
let root_dir = PathBuf::from("/tmp/base");
488+
489+
let temp_dir = tempdir().unwrap();
490+
let remote_dir = temp_dir.path().to_path_buf();
491+
470492
let download_dir = get_temp_package_path(
471-
&root_dir,
493+
&remote_dir,
472494
&agent_id,
473495
&TEST_PACKAGE_ID.to_string(),
474496
&test_reference(),
@@ -496,7 +518,7 @@ mod tests {
496518
let pm = OCIPackageManager {
497519
downloader,
498520
directory_manager,
499-
remote_dir: PathBuf::from("/tmp/base"),
521+
remote_dir,
500522
};
501523
let package_data = PackageData {
502524
id: TEST_PACKAGE_ID.to_string(),
@@ -517,9 +539,12 @@ mod tests {
517539
let mut directory_manager = MockDirectoryManager::new();
518540

519541
let agent_id = AgentID::try_from("agent-id").unwrap();
520-
let root_dir = PathBuf::from("/tmp/base");
542+
543+
let temp_dir = tempdir().unwrap();
544+
let remote_dir = temp_dir.path().to_path_buf();
545+
521546
let download_dir = get_temp_package_path(
522-
&root_dir,
547+
&remote_dir,
523548
&agent_id,
524549
&TEST_PACKAGE_ID.to_string(),
525550
&test_reference(),
@@ -547,7 +572,7 @@ mod tests {
547572
let pm = OCIPackageManager {
548573
downloader,
549574
directory_manager,
550-
remote_dir: PathBuf::from("/tmp/base"),
575+
remote_dir,
551576
};
552577
let package_data = PackageData {
553578
id: TEST_PACKAGE_ID.to_string(),
@@ -568,9 +593,12 @@ mod tests {
568593
let mut directory_manager = MockDirectoryManager::new();
569594

570595
let agent_id = AgentID::try_from("agent-id").unwrap();
571-
let root_dir = PathBuf::from("/tmp/base");
596+
597+
let temp_dir = tempdir().unwrap();
598+
let remote_dir = temp_dir.path().to_path_buf();
599+
572600
let download_dir = get_temp_package_path(
573-
&root_dir,
601+
&remote_dir,
574602
&agent_id,
575603
&TEST_PACKAGE_ID.to_string(),
576604
&test_reference(),
@@ -579,7 +607,7 @@ mod tests {
579607

580608
let downloaded_file = download_dir.join("layer_digest.tar.gz");
581609
let install_dir = get_package_path(
582-
&root_dir,
610+
&remote_dir,
583611
&agent_id,
584612
&TEST_PACKAGE_ID.to_string(),
585613
&test_reference(),
@@ -613,7 +641,7 @@ mod tests {
613641
let pm = OCIPackageManager {
614642
downloader,
615643
directory_manager,
616-
remote_dir: PathBuf::from("/tmp/base"),
644+
remote_dir,
617645
};
618646
let package_data = PackageData {
619647
id: TEST_PACKAGE_ID.to_string(),
@@ -631,17 +659,20 @@ mod tests {
631659
let mut directory_manager = MockDirectoryManager::new();
632660

633661
let agent_id = AgentID::try_from("agent-id").unwrap();
634-
let root_dir = PathBuf::from("/tmp/base");
662+
663+
let temp_dir = tempdir().unwrap();
664+
let remote_dir = temp_dir.path().to_path_buf();
665+
635666
let download_dir = get_temp_package_path(
636-
&root_dir,
667+
&remote_dir,
637668
&agent_id,
638669
&TEST_PACKAGE_ID.to_string(),
639670
&test_reference(),
640671
)
641672
.unwrap();
642673

643674
let install_dir = get_package_path(
644-
&root_dir,
675+
&remote_dir,
645676
&agent_id,
646677
&TEST_PACKAGE_ID.to_string(),
647678
&test_reference(),
@@ -687,7 +718,7 @@ mod tests {
687718
let pm = OCIPackageManager {
688719
downloader,
689720
directory_manager,
690-
remote_dir: PathBuf::from("/tmp/base"),
721+
remote_dir,
691722
};
692723
let package_data = PackageData {
693724
id: TEST_PACKAGE_ID.to_string(),
@@ -741,7 +772,10 @@ mod tests {
741772
.once()
742773
.returning(|_| Err(io::Error::other("error deleting directory")));
743774

744-
let pm = OCIPackageManager::new(downloader, directory_manager, PathBuf::from("/tmp/base"));
775+
let temp_dir = tempdir().unwrap();
776+
777+
let pm =
778+
OCIPackageManager::new(downloader, directory_manager, temp_dir.path().to_path_buf());
745779
let installed_package = InstalledPackageData {
746780
id: TEST_PACKAGE_ID.to_string(),
747781
installation_path: package_path,
@@ -750,4 +784,43 @@ mod tests {
750784

751785
assert!(matches!(result, Err(OCIPackageManagerError::Uninstall(_))));
752786
}
787+
788+
#[test]
789+
fn test_install_skips_download_if_already_installed() {
790+
let mut downloader = MockOCIDownloader::new();
791+
let agent_id = AgentID::try_from("agent-id").unwrap();
792+
let remote_dir = tempdir().unwrap();
793+
794+
let install_dir = get_package_path(
795+
remote_dir.path(),
796+
&agent_id,
797+
&TEST_PACKAGE_ID.to_string(),
798+
&test_reference(),
799+
)
800+
.unwrap();
801+
802+
std::fs::create_dir_all(&install_dir).expect("Failed to create dir");
803+
804+
downloader.expect_download().times(0);
805+
806+
let pm = OCIPackageManager {
807+
downloader,
808+
directory_manager: DirectoryManagerFs {},
809+
remote_dir: PathBuf::from(remote_dir.path()),
810+
};
811+
812+
let package_data = PackageData {
813+
id: TEST_PACKAGE_ID.to_string(),
814+
package_type: PackageType::Tar,
815+
oci_reference: test_reference(),
816+
};
817+
818+
let result = pm.install(&agent_id, package_data);
819+
820+
assert!(result.is_ok());
821+
let installed = result.unwrap();
822+
823+
assert_eq!(installed.installation_path, install_dir);
824+
assert_eq!(installed.id, TEST_PACKAGE_ID);
825+
}
753826
}

agent-control/tests/on_host/oci_package_management.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,56 @@ fn test_install_and_uninstall_with_oci_registry() {
5959
.unwrap();
6060
assert!(!installation_path.exists());
6161
}
62+
#[test]
63+
#[ignore = "needs oci registry, needs elevated privileges on Windows"]
64+
fn test_install_skips_download_if_exists_with_oci_registry() {
65+
let dir = tempdir().unwrap();
66+
let content_dir = tempdir().unwrap();
67+
68+
let payload_file_source = content_dir.path().join("payload.txt");
69+
std::fs::write(&payload_file_source, "ORIGINAL_CONTENT").unwrap();
70+
71+
let file_to_push = dir.path().join("layer_digest.tar.gz");
72+
73+
TestDataHelper::compress_tar_gz(content_dir.path(), file_to_push.as_path());
74+
75+
let (_artifact_digest, reference) = push_artifact(&file_to_push, REGISTRY_URL);
76+
77+
let temp_dir = tempdir().unwrap();
78+
let base_path = temp_dir.path().to_path_buf();
79+
let package_manager = new_testing_oci_package_manager(base_path.clone());
80+
81+
let agent_id = AgentID::try_from("test-agent").unwrap();
82+
let pkg_id = "test-package-idempotency";
83+
84+
let package_data = PackageData {
85+
id: pkg_id.to_string(),
86+
package_type: Tar,
87+
oci_reference: reference.clone(),
88+
};
89+
90+
let installed_1 = package_manager
91+
.install(&agent_id, package_data.clone())
92+
.expect("First install failed");
93+
94+
let installed_file_path = installed_1.installation_path.join("payload.txt");
95+
assert!(
96+
installed_file_path.exists(),
97+
"Payload file should exist after install"
98+
);
99+
100+
let content_1 = std::fs::read_to_string(&installed_file_path).expect("Failed to read payload");
101+
assert_eq!(content_1, "ORIGINAL_CONTENT");
102+
103+
std::fs::write(&installed_file_path, "MODIFIED_CONTENT_BY_USER").unwrap();
104+
105+
let result_2 = package_manager.install(&agent_id, package_data);
106+
assert!(result_2.is_ok());
107+
108+
let content_2 = std::fs::read_to_string(&installed_file_path).unwrap();
109+
110+
assert_eq!(
111+
content_2, "MODIFIED_CONTENT_BY_USER",
112+
"The package manager overwrote the existing files! It should have skipped download/extraction."
113+
);
114+
}

0 commit comments

Comments
 (0)