Page Menu
Home
DevCentral
Search
Configure Global Search
Log In
Files
F6740900
D1868.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
D1868.diff
View Options
diff --git a/Cargo.toml b/Cargo.toml
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,5 +7,9 @@
[dependencies]
env_logger = "^0.5.13"
limiting-factor = { path = "../limiting-factor", features = ["minimal"] }
+log = "^0.4.5"
rocket = "^0.3.16"
rocket_codegen = "^0.3.16"
+rocket_contrib = { version = "*", features = ["json"] }
+serde = "1.0"
+serde_derive = "1.0"
diff --git a/src/app.rs b/src/app.rs
--- a/src/app.rs
+++ b/src/app.rs
@@ -8,6 +8,7 @@
let routes = routes![
status,
favicon,
+ get_registry_stats,
];
MinimalApplication::start_application(routes);
diff --git a/src/lib.rs b/src/lib.rs
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,5 +1,11 @@
#![feature(plugin)]
#![plugin(rocket_codegen)]
+#[macro_use]
+extern crate log;
+
+extern crate rocket_contrib;
+
pub mod app;
+pub mod registry;
pub mod requests;
diff --git a/src/registry.rs b/src/registry.rs
new file mode 100644
--- /dev/null
+++ b/src/registry.rs
@@ -0,0 +1,83 @@
+use serde_derive::{Deserialize, Serialize};
+use std::fs::{DirEntry, read_dir};
+use std::io::Result as IOResult;
+use std::path::Path;
+
+/* -------------------------------------------------------------
+ Registry
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+/// Represents a Docker registry
+#[serde(rename_all = "camelCase")]
+#[derive(Serialize, Deserialize)]
+pub struct Registry {
+ #[serde(skip_serializing)]
+ pub directory: String,
+
+ pub repositories_count: i32
+}
+
+impl Registry {
+ const DEFAULT_LOCATION: &'static str = "/var/lib/registry";
+
+ pub fn new (directory: String) -> Self {
+ let mut registry = Registry {
+ directory,
+ repositories_count: 0,
+ };
+
+ registry.update_stats();
+
+ registry
+ }
+
+ pub fn with_default_location () -> Self {
+ Self::new(String::from(Self::DEFAULT_LOCATION))
+ }
+
+ pub fn update_stats (&mut self) {
+ self.repositories_count = self.count_repositories();
+ }
+
+ pub fn count_repositories (&self) -> i32 {
+ let path_name = format!("{}/docker/registry/v2/repositories", self.directory);
+ let path = Path::new(&path_name);
+
+ if path.exists() && path.is_dir() {
+ match count_subdirectories(path) {
+ Ok(n) => n as i32,
+ Err(e) => {
+ error!(target: "api", "Can't count registry directories: {}", e);
+
+ 0
+ }
+ }
+ } else {
+ error!(target: "api",
+ "Registry path doesn't exist or isn't a directory: {}",
+ path_name);
+
+ 0
+ }
+ }
+}
+
+
+/* -------------------------------------------------------------
+ File system helper functions
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+fn count_subdirectories (dir: &Path) -> IOResult<usize> {
+ let count = read_dir(dir)?
+ .filter(|entry| is_entry_sub_directory(entry))
+ .count();
+
+ Ok(count)
+}
+
+fn is_entry_sub_directory(entry: &IOResult<DirEntry>) -> bool {
+ match entry {
+ Ok(e) => e.path().is_dir(),
+ Err(_) => false,
+ }
+}
diff --git a/src/requests.rs b/src/requests.rs
--- a/src/requests.rs
+++ b/src/requests.rs
@@ -2,6 +2,8 @@
//! Requests handled by the microservice.
//!
+use crate::registry::Registry;
+use limiting_factor::api::replies::{ApiJsonResponse, ApiResponse};
use rocket::response::NamedFile;
#[get("/status")]
@@ -13,3 +15,13 @@
pub fn favicon() -> Option<NamedFile> {
NamedFile::open("assets/favicon.ico").ok()
}
+
+// -------------------------------------------------------------
+// /registry
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+#[get("/registry/stats")]
+pub fn get_registry_stats() -> ApiJsonResponse<Registry> {
+ Registry::with_default_location()
+ .into_json_response()
+}
diff --git a/tests/broken-registry b/tests/broken-registry
new file mode 100644
diff --git a/tests/lib.rs b/tests/lib.rs
new file mode 100644
--- /dev/null
+++ b/tests/lib.rs
@@ -0,0 +1,22 @@
+use docker_registry_api::registry::Registry;
+
+#[test]
+fn test_registry_stats() {
+ let registry = Registry::new("tests/registry".to_string());
+
+ assert_eq!(3, registry.count_repositories()); // Lorem, ipsum, dolor
+}
+
+#[test]
+fn test_registry_stats_when_registry_is_empty() {
+ let registry = Registry::new("tests/void-registry".to_string());
+
+ assert_eq!(0, registry.count_repositories());
+}
+
+#[test]
+fn test_registry_stats_when_registry_is_a_file() {
+ let registry = Registry::new("tests/broken-registry".to_string());
+
+ assert_eq!(0, registry.count_repositories());
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Apr 9, 01:53 (16 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2555287
Default Alt Text
D1868.diff (4 KB)
Attached To
Mode
D1868: Provide statistics information about the registry
Attached
Detach File
Event Timeline
Log In to Comment