summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/db.rs68
-rw-r--r--src/main.rs49
2 files changed, 69 insertions, 48 deletions
diff --git a/src/db.rs b/src/db.rs
index 457921a..ae6073f 100644
--- a/src/db.rs
+++ b/src/db.rs
@@ -4,13 +4,13 @@ use rusqlite::OptionalExtension;
pub trait Db {
fn get_image(&self, registry: &str, image: &str) -> Option<(i64, DateTime<Utc>)>;
- fn insert_image(&self, registry: &str, image: &str, last_checked: DateTime<Utc>) -> i64;
+ fn insert_image(&self, registry: &str, image: &str, last_checked: &DateTime<Utc>) -> i64;
fn get_tags_sorted(&self, image_id: i64) -> Vec<String>;
fn delete_tag(&self, image_id: i64, tag: &str);
- fn insert_tag(&self, image_id: i64, tag: &str, fetched_at: DateTime<Utc>);
- fn update_last_checked(&self, image_id: i64, last_checked: DateTime<Utc>);
+ fn insert_tag(&self, image_id: i64, tag: &str, fetched_at: &DateTime<Utc>);
+ fn update_last_checked(&self, image_id: i64, last_checked: &DateTime<Utc>);
fn get_tag_digest(&self, image_id: i64, tag: &str) -> Option<String>;
- fn update_tag_digest(&self, image_id: i64, tag: &str, digest: &str, fetched_at: DateTime<Utc>);
+ fn update_tag_digest(&self, image_id: i64, tag: &str, digest: &str, fetched_at: &DateTime<Utc>);
}
pub struct SqliteDb {
@@ -113,7 +113,7 @@ impl Db for SqliteDb {
))).optional().unwrap();
}
- fn insert_image(&self, registry: &str, image: &str, last_checked: DateTime<Utc>) -> i64 {
+ fn insert_image(&self, registry: &str, image: &str, last_checked: &DateTime<Utc>) -> i64 {
let _timer = crate::metrics::get().db_query_duration.start_timer();
self.conn.execute("
INSERT INTO images(registry, image, last_checked) VALUES (?1, ?2, ?3)
@@ -138,13 +138,13 @@ impl Db for SqliteDb {
(image_id, tag)).unwrap();
}
- fn insert_tag(&self, image_id: i64, tag: &str, fetched_at: DateTime<Utc>) {
+ fn insert_tag(&self, image_id: i64, tag: &str, fetched_at: &DateTime<Utc>) {
let _timer = crate::metrics::get().db_query_duration.start_timer();
self.conn.execute("INSERT INTO tags(image_id, tag, fetched_at) VALUES (?1, ?2, ?3)",
(image_id, tag, fetched_at)).unwrap();
}
- fn update_last_checked(&self, image_id: i64, last_checked: DateTime<Utc>) {
+ fn update_last_checked(&self, image_id: i64, last_checked: &DateTime<Utc>) {
let _timer = crate::metrics::get().db_query_duration.start_timer();
self.conn.execute("UPDATE images SET last_checked = ?1 WHERE id = ?2", (last_checked, image_id)).unwrap();
}
@@ -156,7 +156,7 @@ impl Db for SqliteDb {
", (image_id, tag), |row| row.get::<_, String>(0)).optional().unwrap();
}
- fn update_tag_digest(&self, image_id: i64, tag: &str, digest: &str, fetched_at: DateTime<Utc>) {
+ fn update_tag_digest(&self, image_id: i64, tag: &str, digest: &str, fetched_at: &DateTime<Utc>) {
let _timer = crate::metrics::get().db_query_duration.start_timer();
self.conn.execute("UPDATE tags SET digest = ?1, fetched_at = ?2 WHERE image_id = ?3 AND tag = ?4",
(digest, fetched_at, image_id, tag)).unwrap();
@@ -192,10 +192,10 @@ impl Db for StubDb {
return None;
}
- fn insert_image(&self, registry: &str, image: &str, last_checked: DateTime<Utc>) -> i64 {
+ fn insert_image(&self, registry: &str, image: &str, last_checked: &DateTime<Utc>) -> i64 {
let id = *self.next_id.borrow();
*self.next_id.borrow_mut() += 1;
- self.images.borrow_mut().push((registry.to_string(), image.to_string(), id, last_checked));
+ self.images.borrow_mut().push((registry.to_string(), image.to_string(), id, last_checked.clone()));
return id;
}
@@ -214,14 +214,14 @@ impl Db for StubDb {
self.tags.borrow_mut().retain(|(id, t, _, _)| !(*id == image_id && t == tag));
}
- fn insert_tag(&self, image_id: i64, tag: &str, fetched_at: DateTime<Utc>) {
- self.tags.borrow_mut().push((image_id, tag.to_string(), None, fetched_at));
+ fn insert_tag(&self, image_id: i64, tag: &str, fetched_at: &DateTime<Utc>) {
+ self.tags.borrow_mut().push((image_id, tag.to_string(), None, fetched_at.clone()));
}
- fn update_last_checked(&self, image_id: i64, last_checked: DateTime<Utc>) {
+ fn update_last_checked(&self, image_id: i64, last_checked: &DateTime<Utc>) {
for (_, _, id, lc) in self.images.borrow_mut().iter_mut() {
if *id == image_id {
- *lc = last_checked;
+ *lc = last_checked.clone();
return;
}
}
@@ -236,11 +236,11 @@ impl Db for StubDb {
return None;
}
- fn update_tag_digest(&self, image_id: i64, tag: &str, digest: &str, fetched_at: DateTime<Utc>) {
+ fn update_tag_digest(&self, image_id: i64, tag: &str, digest: &str, fetched_at: &DateTime<Utc>) {
for (id, t, d, fa) in self.tags.borrow_mut().iter_mut() {
if *id == image_id && t == tag {
*d = Some(digest.to_string());
- *fa = fetched_at;
+ *fa = fetched_at.clone();
return;
}
}
@@ -254,8 +254,8 @@ mod tests {
fn test_insert_image_returns_incrementing_ids(db: &dyn Db) {
let now = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
- let id1 = db.insert_image("docker.io", "nginx", now);
- let id2 = db.insert_image("docker.io", "redis", now);
+ let id1 = db.insert_image("docker.io", "nginx", &now);
+ let id2 = db.insert_image("docker.io", "redis", &now);
assert!(id2 > id1);
}
@@ -265,7 +265,7 @@ mod tests {
fn test_get_image_returns_inserted(db: &dyn Db) {
let now = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
- let id = db.insert_image("docker.io", "nginx", now);
+ let id = db.insert_image("docker.io", "nginx", &now);
let (got_id, got_time) = db.get_image("docker.io", "nginx").unwrap();
assert_eq!(got_id, id);
assert_eq!(got_time, now);
@@ -273,24 +273,24 @@ mod tests {
fn test_get_tags_returns_empty_for_no_tags(db: &dyn Db) {
let now = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
- let id = db.insert_image("docker.io", "nginx", now);
+ let id = db.insert_image("docker.io", "nginx", &now);
assert_eq!(db.get_tags_sorted(id), Vec::<String>::new());
}
fn test_get_tags_returns_sorted(db: &dyn Db) {
let now = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
- let id = db.insert_image("docker.io", "nginx", now);
- db.insert_tag(id, "2.0", now);
- db.insert_tag(id, "1.0", now);
- db.insert_tag(id, "latest", now);
+ let id = db.insert_image("docker.io", "nginx", &now);
+ db.insert_tag(id, "2.0", &now);
+ db.insert_tag(id, "1.0", &now);
+ db.insert_tag(id, "latest", &now);
assert_eq!(db.get_tags_sorted(id), vec!["1.0", "2.0", "latest"]);
}
fn test_delete_tag_removes_tag(db: &dyn Db) {
let now = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
- let id = db.insert_image("docker.io", "nginx", now);
- db.insert_tag(id, "1.0", now);
- db.insert_tag(id, "2.0", now);
+ let id = db.insert_image("docker.io", "nginx", &now);
+ db.insert_tag(id, "1.0", &now);
+ db.insert_tag(id, "2.0", &now);
db.delete_tag(id, "1.0");
assert_eq!(db.get_tags_sorted(id), vec!["2.0"]);
}
@@ -298,23 +298,23 @@ mod tests {
fn test_update_last_checked(db: &dyn Db) {
let t1 = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
let t2 = Utc.with_ymd_and_hms(2000, 1, 1, 1, 0, 0).unwrap();
- let id = db.insert_image("docker.io", "nginx", t1);
- db.update_last_checked(id, t2);
+ let id = db.insert_image("docker.io", "nginx", &t1);
+ db.update_last_checked(id, &t2);
assert_eq!(db.get_image("docker.io", "nginx").unwrap().1, t2);
}
fn test_get_tag_digest_returns_none_when_unset(db: &dyn Db) {
let now = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
- let id = db.insert_image("docker.io", "nginx", now);
- db.insert_tag(id, "1.0", now);
+ let id = db.insert_image("docker.io", "nginx", &now);
+ db.insert_tag(id, "1.0", &now);
assert_eq!(db.get_tag_digest(id, "1.0"), None);
}
fn test_update_tag_digest(db: &dyn Db) {
let now = Utc.with_ymd_and_hms(2000, 1, 1, 0, 0, 0).unwrap();
- let id = db.insert_image("docker.io", "nginx", now);
- db.insert_tag(id, "1.0", now);
- db.update_tag_digest(id, "1.0", "sha256:abc", now);
+ let id = db.insert_image("docker.io", "nginx", &now);
+ db.insert_tag(id, "1.0", &now);
+ db.update_tag_digest(id, "1.0", "sha256:abc", &now);
assert_eq!(db.get_tag_digest(id, "1.0"), Some("sha256:abc".to_string()));
}
diff --git a/src/main.rs b/src/main.rs
index ed3c9d5..680bc9f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -52,32 +52,52 @@ struct FileInput {
images: Vec<Range<usize>>,
}
-fn update_images(db: &dyn Db, reg: &dyn Registry, files: &[FileInput], outcomes: &mut Vec<Result<Vec<FilePatch>, String>>) {
+fn update_images(now: &chrono::DateTime<chrono::Utc>, db: &dyn Db, reg: &dyn Registry, files: &[FileInput], outcomes: &mut Vec<Result<Vec<FilePatch>, String>>) {
for file in files {
let mut patches = vec![];
let mut error: Option<String> = None;
+ let mut imgs: Vec<DockerRef> = vec![];
+ let mut image_ids: Vec<i64> = vec![];
+ let mut last_checkeds: Vec<chrono::DateTime<chrono::Utc>> = vec![];
+
for image in &file.images {
- println!("Checking image {}", &file.content[image.clone()]);
let img = DockerRef::parse(&file.content, image);
- let registry = img.registry.as_ref().map(|x| &file.content[x.clone()]).unwrap_or("registry.hub.docker.com");
- let mut tag = img.tag.as_ref().map(|x| file.content[x.clone()].to_string());
+ let registry = img.registry.as_ref()
+ .map(|x| &file.content[x.clone()])
+ .unwrap_or("registry.hub.docker.com");
let image_name = &file.content[img.image.clone()];
- metrics::get().images_checked.with_label_values(&[registry]).inc();
-
- let now = chrono::offset::Utc::now();
- let cache_max_age = chrono::Duration::hours(24);
-
let (image_id, last_checked) = match db.get_image(registry, image_name) {
Some(x) => x,
None => {
- let id = db.insert_image(registry, image_name, now);
- (id, now)
+ let epoch = chrono::DateTime::<chrono::Utc>::UNIX_EPOCH;
+ let id = db.insert_image(registry, image_name, &epoch);
+ (id, epoch)
},
};
- let cache_stale = now - last_checked > cache_max_age;
+ imgs.push(img);
+ image_ids.push(image_id);
+ last_checkeds.push(last_checked);
+ }
+
+ let cache_max_age = chrono::Duration::hours(24);
+
+ for i in 0..imgs.len() {
+ let img = &imgs[i];
+ let registry = img.registry.as_ref()
+ .map(|x| &file.content[x.clone()])
+ .unwrap_or("registry.hub.docker.com");
+ let mut tag = img.tag.as_ref().map(|x| file.content[x.clone()].to_string());
+ let image_name = &file.content[img.image.clone()];
+ let image_id = image_ids[i];
+ let last_checked = last_checkeds[i];
+
+ println!("Checking image {}", &file.content[file.images[i].clone()]);
+ metrics::get().images_checked.with_label_values(&[registry]).inc();
+
+ let cache_stale = *now - last_checked > cache_max_age;
let cached_tags: Vec<String> = db.get_tags_sorted(image_id);
@@ -143,7 +163,7 @@ fn update_images(db: &dyn Db, reg: &dyn Registry, files: &[FileInput], outcomes:
if let Some(new_tag) = new_tag {
tag = Some(new_tag.clone());
patches.push(FilePatch {
- position: img.tag.unwrap(),
+ position: img.tag.clone().unwrap(),
content: new_tag,
});
metrics::get().images_updated.with_label_values(&[registry]).inc();
@@ -393,8 +413,9 @@ fn run_tool(db: &dyn Db, reg: &dyn Registry, repos: &Vec<Repository>, mut infile
file_inputs.push(FileInput { path, content, images });
}
+ let now = chrono::offset::Utc::now();
let mut outcomes: Vec<Result<Vec<FilePatch>, String>> = Vec::with_capacity(file_inputs.len());
- update_images(db, reg, &file_inputs, &mut outcomes);
+ update_images(&now, db, reg, &file_inputs, &mut outcomes);
for i in 0..file_inputs.len() {
let file = &file_inputs[i];