From 5c51a9bdafda4987ab7da52b816e01ea6b56502d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Thu, 11 Mar 2021 11:14:41 +0100 Subject: Endpoint configuration as Map This patch rewrites the endpoint configuration format to be a map. The problem here is, that a list of endpoints cannot easily be used with layered configuration, where a part of the configuration lives in the XDG config home of the user and the rest lives in the repository. With this patch, the endpoints are configured with a map instead of an array, which makes it less complicated to overwrite. The name of an endpoint is now the key in the map. A type `EndpointName` was introduced to take advantage of strong typing. Thus, the patch touches a bit more code to adapt to the new type in use. Signed-off-by: Matthias Beyer Tested-by: Matthias Beyer --- config.toml | 3 +-- examples/packages/repo/config.toml | 6 ++---- src/commands/build.rs | 6 +++--- src/commands/endpoint.rs | 28 +++++++++++++++------------- src/commands/endpoint_container.rs | 3 ++- src/config/docker_config.rs | 5 ++++- src/config/endpoint_config.rs | 27 +++++++++++++++++++++++---- src/db/models/endpoint.rs | 7 ++++--- src/endpoint/configuration.rs | 3 +++ src/endpoint/configured.rs | 19 ++++++++++--------- 10 files changed, 67 insertions(+), 40 deletions(-) diff --git a/config.toml b/config.toml index 15843de..46fc7cc 100644 --- a/config.toml +++ b/config.toml @@ -170,8 +170,7 @@ verify_images_present = true # List of docker endpoints # -[[docker.endpoints]] -name = "testhostname" +[docker.endpoints.testhostname] uri = "http://0.0.0.0:8095" # the URI of the endpoint. Either http or socket path endpoint_type = "http" # either "http" or "socket" diff --git a/examples/packages/repo/config.toml b/examples/packages/repo/config.toml index 34fb996..5701f5c 100644 --- a/examples/packages/repo/config.toml +++ b/examples/packages/repo/config.toml @@ -40,11 +40,9 @@ images = [ "debian:bullseye" ] verify_images_present = true # -# List of docker endpoints +# Docker endpoints # - -[[docker.endpoints]] -name = "testhostname" +[docker.endpoints.testhostname] uri = "http://0.0.0.0:8095" # the URI of the endpoint. Either http or socket path endpoint_type = "http" # either "http" or "socket" speed = 1 # currently ignored, but required to be present diff --git a/src/commands/build.rs b/src/commands/build.rs index 9880552..81077d4 100644 --- a/src/commands/build.rs +++ b/src/commands/build.rs @@ -102,10 +102,10 @@ pub async fn build( .docker() .endpoints() .iter() - .cloned() - .map(|ep_cfg| { + .map(|(ep_name, ep_cfg)| { crate::endpoint::EndpointConfiguration::builder() - .endpoint(ep_cfg) + .endpoint_name(ep_name.clone()) + .endpoint(ep_cfg.clone()) .required_images(config.docker().images().clone()) .required_docker_versions(config.docker().docker_versions().clone()) .required_docker_api_versions(config.docker().docker_api_versions().clone()) diff --git a/src/commands/endpoint.rs b/src/commands/endpoint.rs index c1632e6..5338978 100644 --- a/src/commands/endpoint.rs +++ b/src/commands/endpoint.rs @@ -20,6 +20,7 @@ use itertools::Itertools; use tokio_stream::StreamExt; use crate::config::Configuration; +use crate::config::EndpointName; use crate::util::progress::ProgressBars; use crate::endpoint::Endpoint; @@ -27,12 +28,13 @@ pub async fn endpoint(matches: &ArgMatches, config: &Configuration, progress_gen let endpoint_names = matches .value_of("endpoint_name") .map(String::from) + .map(EndpointName::from) .map(|ep| vec![ep]) .unwrap_or_else(|| { config.docker() .endpoints() .iter() - .map(|ep| ep.name()) + .map(|(ep_name, _)| ep_name) .cloned() .collect() }); @@ -47,7 +49,7 @@ pub async fn endpoint(matches: &ArgMatches, config: &Configuration, progress_gen } } -async fn ping(endpoint_names: Vec, +async fn ping(endpoint_names: Vec, matches: &ArgMatches, config: &Configuration, progress_generator: ProgressBars @@ -94,7 +96,7 @@ async fn ping(endpoint_names: Vec, tokio::join!(ping_process, multibar_block).0 } -async fn stats(endpoint_names: Vec, +async fn stats(endpoint_names: Vec, matches: &ArgMatches, config: &Configuration, progress_generator: ProgressBars @@ -155,7 +157,7 @@ async fn stats(endpoint_names: Vec, } -async fn containers(endpoint_names: Vec, +async fn containers(endpoint_names: Vec, matches: &ArgMatches, config: &Configuration, ) -> Result<()> { @@ -167,7 +169,7 @@ async fn containers(endpoint_names: Vec, } } -async fn containers_list(endpoint_names: Vec, +async fn containers_list(endpoint_names: Vec, matches: &ArgMatches, config: &Configuration, ) -> Result<()> { @@ -204,7 +206,7 @@ async fn containers_list(endpoint_names: Vec, .filter(|stat| newer_than_filter.as_ref().map(|time| time < &stat.created).unwrap_or(true)) .map(|stat| { vec![ - endpoint_name.clone(), + endpoint_name.as_ref().to_owned(), stat.id, stat.image, stat.created.to_string(), @@ -219,7 +221,7 @@ async fn containers_list(endpoint_names: Vec, crate::commands::util::display_data(hdr, data, csv) } -async fn containers_prune(endpoint_names: Vec, +async fn containers_prune(endpoint_names: Vec, matches: &ArgMatches, config: &Configuration, ) -> Result<()> { @@ -274,16 +276,16 @@ fn get_date_filter(name: &str, matches: &ArgMatches) -> Result Result>> { +pub(super) async fn connect_to_endpoints(config: &Configuration, endpoint_names: &[EndpointName]) -> Result>> { let endpoint_configurations = config .docker() .endpoints() .iter() - .filter(|ep| endpoint_names.contains(ep.name())) - .cloned() - .map(|ep_cfg| { + .filter(|(ep_name, _)| endpoint_names.contains(ep_name)) + .map(|(ep_name, ep_cfg)| { crate::endpoint::EndpointConfiguration::builder() - .endpoint(ep_cfg) + .endpoint_name(ep_name.clone()) + .endpoint(ep_cfg.clone()) .required_images(config.docker().images().clone()) .required_docker_versions(config.docker().docker_versions().clone()) .required_docker_api_versions(config.docker().docker_api_versions().clone()) @@ -294,7 +296,7 @@ pub(super) async fn connect_to_endpoints(config: &Configuration, endpoint_names: info!("Endpoint config build"); info!("Connecting to {n} endpoints: {eps}", n = endpoint_configurations.len(), - eps = endpoint_configurations.iter().map(|epc| epc.endpoint().name()).join(", ")); + eps = endpoint_configurations.iter().map(|epc| epc.endpoint_name()).join(", ")); crate::endpoint::util::setup_endpoints(endpoint_configurations).await } diff --git a/src/commands/endpoint_container.rs b/src/commands/endpoint_container.rs index 1861cc7..962b62c 100644 --- a/src/commands/endpoint_container.rs +++ b/src/commands/endpoint_container.rs @@ -18,8 +18,9 @@ use tokio_stream::StreamExt; use shiplift::Container; use crate::config::Configuration; +use crate::config::EndpointName; -pub async fn container(endpoint_names: Vec, +pub async fn container(endpoint_names: Vec, matches: &ArgMatches, config: &Configuration, ) -> Result<()> { diff --git a/src/config/docker_config.rs b/src/config/docker_config.rs index 1cef561..f7cd1db 100644 --- a/src/config/docker_config.rs +++ b/src/config/docker_config.rs @@ -8,10 +8,13 @@ // SPDX-License-Identifier: EPL-2.0 // +use std::collections::HashMap; + use getset::{CopyGetters, Getters}; use serde::Deserialize; use crate::config::Endpoint; +use crate::config::EndpointName; use crate::util::docker::ImageName; /// Configuration of the docker daemon interfacing functionality @@ -48,5 +51,5 @@ pub struct DockerConfig { images: Vec, #[getset(get = "pub")] - endpoints: Vec, + endpoints: HashMap, } diff --git a/src/config/endpoint_config.rs b/src/config/endpoint_config.rs index 13db137..69405dc 100644 --- a/src/config/endpoint_config.rs +++ b/src/config/endpoint_config.rs @@ -11,13 +11,31 @@ use getset::{CopyGetters, Getters}; use serde::Deserialize; +#[derive(Debug, Clone, Deserialize, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[serde(transparent)] +pub struct EndpointName(String); + +impl From for EndpointName { + fn from(s: String) -> Self { + EndpointName(s) + } +} + +impl std::fmt::Display for EndpointName { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { + self.0.fmt(f) + } +} + +impl AsRef for EndpointName { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} + /// Configuration of a single endpoint #[derive(Clone, Debug, Getters, CopyGetters, Deserialize)] pub struct Endpoint { - /// A human-readable name of the endpoint - #[getset(get = "pub")] - name: String, - /// The URI where the endpoint is reachable #[getset(get = "pub")] uri: String, @@ -42,3 +60,4 @@ pub enum EndpointType { #[serde(rename = "http")] Http, } + diff --git a/src/db/models/endpoint.rs b/src/db/models/endpoint.rs index 73009f6..d7a7986 100644 --- a/src/db/models/endpoint.rs +++ b/src/db/models/endpoint.rs @@ -13,6 +13,7 @@ use anyhow::Result; use diesel::prelude::*; use diesel::PgConnection; +use crate::config::EndpointName; use crate::schema::endpoints; use crate::schema::endpoints::*; @@ -29,8 +30,8 @@ struct NewEndpoint<'a> { } impl Endpoint { - pub fn create_or_fetch(database_connection: &PgConnection, ep_name: &str) -> Result { - let new_ep = NewEndpoint { name: ep_name }; + pub fn create_or_fetch(database_connection: &PgConnection, ep_name: &EndpointName) -> Result { + let new_ep = NewEndpoint { name: ep_name.as_ref() }; diesel::insert_into(endpoints::table) .values(&new_ep) @@ -38,7 +39,7 @@ impl Endpoint { .execute(database_connection)?; dsl::endpoints - .filter(name.eq(ep_name)) + .filter(name.eq(ep_name.as_ref())) .first::(database_connection) .map_err(Error::from) } diff --git a/src/endpoint/configuration.rs b/src/endpoint/configuration.rs index a9b4688..bdabd08 100644 --- a/src/endpoint/configuration.rs +++ b/src/endpoint/configuration.rs @@ -15,6 +15,9 @@ use crate::util::docker::ImageName; #[derive(Getters, TypedBuilder)] pub struct EndpointConfiguration { + #[getset(get = "pub")] + endpoint_name: crate::config::EndpointName, + #[getset(get = "pub")] endpoint: crate::config::Endpoint, diff --git a/src/endpoint/configured.rs b/src/endpoint/configured.rs index 7265dd6..f850ff6 100644 --- a/src/endpoint/configured.rs +++ b/src/endpoint/configured.rs @@ -28,6 +28,7 @@ use tokio::sync::RwLock; use tokio_stream::StreamExt; use typed_builder::TypedBuilder; +use crate::config::EndpointName; use crate::endpoint::EndpointConfiguration; use crate::filestore::ReleaseStore; use crate::filestore::StagingStore; @@ -43,7 +44,7 @@ use crate::util::docker::ImageName; #[derive(Getters, CopyGetters, TypedBuilder)] pub struct Endpoint { #[getset(get = "pub")] - name: String, + name: EndpointName, #[getset(get = "pub")] docker: Docker, @@ -69,10 +70,10 @@ impl Debug for Endpoint { impl Endpoint { pub(super) async fn setup(epc: EndpointConfiguration) -> Result { - let ep = Endpoint::setup_endpoint(epc.endpoint()).with_context(|| { + let ep = Endpoint::setup_endpoint(epc.endpoint_name(), epc.endpoint()).with_context(|| { anyhow!( "Setting up endpoint: {} -> {}", - epc.endpoint().name(), + epc.endpoint_name(), epc.endpoint().uri() ) })?; @@ -89,21 +90,21 @@ impl Endpoint { let _ = versions_compat.with_context(|| { anyhow!( "Checking version compatibility for {} -> {}", - epc.endpoint().name(), + epc.endpoint_name(), epc.endpoint().uri() ) })?; let _ = api_versions_compat.with_context(|| { anyhow!( "Checking API version compatibility for {} -> {}", - epc.endpoint().name(), + epc.endpoint_name(), epc.endpoint().uri() ) })?; let _ = imgs_avail.with_context(|| { anyhow!( "Checking for available images on {} -> {}", - epc.endpoint().name(), + epc.endpoint_name(), epc.endpoint().uri() ) })?; @@ -111,7 +112,7 @@ impl Endpoint { Ok(ep) } - fn setup_endpoint(ep: &crate::config::Endpoint) -> Result { + fn setup_endpoint(ep_name: &EndpointName, ep: &crate::config::Endpoint) -> Result { match ep.endpoint_type() { crate::config::EndpointType::Http => shiplift::Uri::from_str(ep.uri()) .map(shiplift::Docker::host) @@ -119,7 +120,7 @@ impl Endpoint { .map_err(Error::from) .map(|docker| { Endpoint::builder() - .name(ep.name().clone()) + .name(ep_name.clone()) .uri(ep.uri().clone()) .docker(docker) .num_max_jobs(ep.maxjobs()) @@ -129,7 +130,7 @@ impl Endpoint { crate::config::EndpointType::Socket => Ok({ Endpoint::builder() - .name(ep.name().clone()) + .name(ep_name.clone()) .uri(ep.uri().clone()) .num_max_jobs(ep.maxjobs()) .network_mode(ep.network_mode().clone()) -- cgit v1.2.3