Compare commits
	
		
			No commits in common. "28476af222d76ee28ff36d1aa9eca7a871e44505" and "6de889aa0f7376e663602398686bd86c32005099" have entirely different histories.
		
	
	
		
			28476af222
			...
			6de889aa0f
		
	
		
							
								
								
									
										36
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										36
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -1355,7 +1355,6 @@ dependencies = [ | |||||||
| name = "example-rust" | name = "example-rust" | ||||||
| version = "0.1.0" | version = "0.1.0" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "base64 0.22.1", |  | ||||||
|  "env_logger", |  "env_logger", | ||||||
|  "harmony", |  "harmony", | ||||||
|  "harmony_cli", |  "harmony_cli", | ||||||
| @ -1428,18 +1427,6 @@ version = "0.2.9" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" | checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" | ||||||
| 
 | 
 | ||||||
| [[package]] |  | ||||||
| name = "filetime" |  | ||||||
| version = "0.2.25" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" |  | ||||||
| dependencies = [ |  | ||||||
|  "cfg-if", |  | ||||||
|  "libc", |  | ||||||
|  "libredox", |  | ||||||
|  "windows-sys 0.59.0", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "flate2" | name = "flate2" | ||||||
| version = "1.1.2" | version = "1.1.2" | ||||||
| @ -1779,7 +1766,6 @@ dependencies = [ | |||||||
|  "serde_yaml", |  "serde_yaml", | ||||||
|  "similar", |  "similar", | ||||||
|  "strum 0.27.1", |  "strum 0.27.1", | ||||||
|  "tar", |  | ||||||
|  "temp-dir", |  "temp-dir", | ||||||
|  "temp-file", |  "temp-file", | ||||||
|  "tempfile", |  "tempfile", | ||||||
| @ -2743,7 +2729,6 @@ checksum = "1580801010e535496706ba011c15f8532df6b42297d2e471fec38ceadd8c0638" | |||||||
| dependencies = [ | dependencies = [ | ||||||
|  "bitflags 2.9.1", |  "bitflags 2.9.1", | ||||||
|  "libc", |  "libc", | ||||||
|  "redox_syscall", |  | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| @ -4712,17 +4697,6 @@ version = "1.0.1" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" | checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" | ||||||
| 
 | 
 | ||||||
| [[package]] |  | ||||||
| name = "tar" |  | ||||||
| version = "0.4.44" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" |  | ||||||
| dependencies = [ |  | ||||||
|  "filetime", |  | ||||||
|  "libc", |  | ||||||
|  "xattr", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "temp-dir" | name = "temp-dir" | ||||||
| version = "0.1.16" | version = "0.1.16" | ||||||
| @ -5768,16 +5742,6 @@ dependencies = [ | |||||||
|  "tap", |  "tap", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
| [[package]] |  | ||||||
| name = "xattr" |  | ||||||
| version = "1.5.1" |  | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" |  | ||||||
| checksum = "af3a19837351dc82ba89f8a125e22a3c475f05aba604acc023d62b2739ae2909" |  | ||||||
| dependencies = [ |  | ||||||
|  "libc", |  | ||||||
|  "rustix 1.0.7", |  | ||||||
| ] |  | ||||||
| 
 |  | ||||||
| [[package]] | [[package]] | ||||||
| name = "xml-rs" | name = "xml-rs" | ||||||
| version = "0.8.26" | version = "0.8.26" | ||||||
|  | |||||||
| @ -54,5 +54,3 @@ similar = "2" | |||||||
| uuid = { version = "1.11", features = ["v4", "fast-rng", "macro-diagnostics"] } | uuid = { version = "1.11", features = ["v4", "fast-rng", "macro-diagnostics"] } | ||||||
| pretty_assertions = "1.4.1" | pretty_assertions = "1.4.1" | ||||||
| bollard = "0.19.1" | bollard = "0.19.1" | ||||||
| base64 = "0.22.1" |  | ||||||
| tar = "0.4.44" |  | ||||||
|  | |||||||
| @ -12,4 +12,3 @@ tokio = { workspace = true } | |||||||
| log = { workspace = true } | log = { workspace = true } | ||||||
| env_logger = { workspace = true } | env_logger = { workspace = true } | ||||||
| url = { workspace = true } | url = { workspace = true } | ||||||
| base64.workspace = true |  | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| use std::{path::PathBuf, sync::Arc}; | use std::{path::PathBuf, sync::Arc}; | ||||||
| 
 | 
 | ||||||
| use base64::{Engine as _, engine::general_purpose}; |  | ||||||
| use harmony::{ | use harmony::{ | ||||||
|     data::Id, |     data::Id, | ||||||
|     inventory::Inventory, |     inventory::Inventory, | ||||||
| @ -10,17 +9,11 @@ use harmony::{ | |||||||
|             ApplicationScore, RustWebFramework, RustWebapp, |             ApplicationScore, RustWebFramework, RustWebapp, | ||||||
|             features::{ContinuousDelivery, Monitoring}, |             features::{ContinuousDelivery, Monitoring}, | ||||||
|         }, |         }, | ||||||
|         monitoring::{ |  | ||||||
|             alert_channel::webhook_receiver::WebhookReceiver, |  | ||||||
|             kube_prometheus::helm_prometheus_alert_score::HelmPrometheusAlertingScore, |  | ||||||
|             ntfy::ntfy::NtfyScore, |  | ||||||
|         }, |  | ||||||
|         tenant::TenantScore, |         tenant::TenantScore, | ||||||
|     }, |     }, | ||||||
|     score::Score, |  | ||||||
|     topology::{ |     topology::{ | ||||||
|         K8sAnywhereTopology, Url, |         K8sAnywhereTopology, Url, | ||||||
|         tenant::{ResourceLimits, TenantConfig, TenantManager, TenantNetworkPolicy}, |         tenant::{ResourceLimits, TenantConfig, TenantNetworkPolicy}, | ||||||
|     }, |     }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| @ -43,17 +36,6 @@ async fn main() { | |||||||
|         }, |         }, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     let topology = K8sAnywhereTopology::from_env(); |  | ||||||
| 
 |  | ||||||
|     // topology
 |  | ||||||
|     //     .provision_tenant(&tenant.config)
 |  | ||||||
|     //     .await
 |  | ||||||
|     //     .expect("couldn't provision tenant");
 |  | ||||||
| 
 |  | ||||||
|     let mut maestro = Maestro::initialize(Inventory::autoload(), topology) |  | ||||||
|         .await |  | ||||||
|         .unwrap(); |  | ||||||
| 
 |  | ||||||
|     let application = Arc::new(RustWebapp { |     let application = Arc::new(RustWebapp { | ||||||
|         name: "harmony-example-rust-webapp".to_string(), |         name: "harmony-example-rust-webapp".to_string(), | ||||||
|         domain: Url::Url(url::Url::parse("https://rustapp.harmony.example.com").unwrap()), |         domain: Url::Url(url::Url::parse("https://rustapp.harmony.example.com").unwrap()), | ||||||
| @ -61,59 +43,21 @@ async fn main() { | |||||||
|         framework: Some(RustWebFramework::Leptos), |         framework: Some(RustWebFramework::Leptos), | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     let ntfy = NtfyScore { |  | ||||||
|         namespace: tenant.clone().config.name, |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     let ntfy_default_auth_username = "harmony"; |  | ||||||
|     let ntfy_default_auth_password = "harmony"; |  | ||||||
|     let ntfy_default_auth_header = format!( |  | ||||||
|         "Basic {}", |  | ||||||
|         general_purpose::STANDARD.encode(format!( |  | ||||||
|             "{ntfy_default_auth_username}:{ntfy_default_auth_password}" |  | ||||||
|         )) |  | ||||||
|     ); |  | ||||||
| 
 |  | ||||||
|     let ntfy_default_auth_param = general_purpose::STANDARD |  | ||||||
|         .encode(ntfy_default_auth_header) |  | ||||||
|         .rsplit("=") |  | ||||||
|         .collect::<Vec<&str>>()[0] |  | ||||||
|         .to_string(); |  | ||||||
| 
 |  | ||||||
|     let ntfy_receiver = WebhookReceiver { |  | ||||||
|         name: "ntfy-webhook".to_string(), |  | ||||||
|         url: Url::Url( |  | ||||||
|             url::Url::parse( |  | ||||||
|                 format!( |  | ||||||
|                     "http://ntfy.{}.svc.cluster.local/rust-web-app?auth={ntfy_default_auth_param}", |  | ||||||
|                     tenant.clone().config.name |  | ||||||
|                 ) |  | ||||||
|                 .as_str(), |  | ||||||
|             ) |  | ||||||
|             .unwrap(), |  | ||||||
|         ), |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     let alerting_score = HelmPrometheusAlertingScore { |  | ||||||
|         receivers: vec![Box::new(ntfy_receiver)], |  | ||||||
|         rules: vec![], |  | ||||||
|         service_monitors: vec![], |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     let app = ApplicationScore { |     let app = ApplicationScore { | ||||||
|         features: vec![ |         features: vec![ | ||||||
|             Box::new(ContinuousDelivery { |             Box::new(ContinuousDelivery { | ||||||
|                 application: application.clone(), |                 application: application.clone(), | ||||||
|             }), // TODO add monitoring, backups, multisite ha, etc
 |             }), | ||||||
|  |             Box::new(Monitoring {}), | ||||||
|  |             // TODO add monitoring, backups, multisite ha, etc
 | ||||||
|         ], |         ], | ||||||
|         application, |         application, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     maestro.register_all(vec![ |     let topology = K8sAnywhereTopology::from_env(); | ||||||
|         Box::new(tenant), |     let mut maestro = Maestro::initialize(Inventory::autoload(), topology) | ||||||
|         Box::new(ntfy), |         .await | ||||||
|         Box::new(alerting_score), |         .unwrap(); | ||||||
|         Box::new(app), |     maestro.register_all(vec![Box::new(tenant), Box::new(app)]); | ||||||
|     ]); |  | ||||||
|     harmony_cli::init(maestro, None).await.unwrap(); |     harmony_cli::init(maestro, None).await.unwrap(); | ||||||
| } | } | ||||||
|  | |||||||
| @ -60,7 +60,6 @@ strum = { version = "0.27.1", features = ["derive"] } | |||||||
| tempfile = "3.20.0" | tempfile = "3.20.0" | ||||||
| serde_with = "3.14.0" | serde_with = "3.14.0" | ||||||
| bollard.workspace = true | bollard.workspace = true | ||||||
| tar.workspace = true |  | ||||||
| 
 | 
 | ||||||
| [dev-dependencies] | [dev-dependencies] | ||||||
| pretty_assertions.workspace = true | pretty_assertions.workspace = true | ||||||
|  | |||||||
| @ -2,10 +2,7 @@ use derive_new::new; | |||||||
| use futures_util::StreamExt; | use futures_util::StreamExt; | ||||||
| use k8s_openapi::{ | use k8s_openapi::{ | ||||||
|     ClusterResourceScope, NamespaceResourceScope, |     ClusterResourceScope, NamespaceResourceScope, | ||||||
|     api::{ |     api::{apps::v1::Deployment, core::v1::Pod}, | ||||||
|         apps::v1::Deployment, |  | ||||||
|         core::v1::{ObjectReference, Pod}, |  | ||||||
|     }, |  | ||||||
| }; | }; | ||||||
| use kube::{ | use kube::{ | ||||||
|     Client, Config, Error, Resource, |     Client, Config, Error, Resource, | ||||||
| @ -247,39 +244,37 @@ impl K8sClient { | |||||||
| 
 | 
 | ||||||
|     pub async fn apply_yaml_many( |     pub async fn apply_yaml_many( | ||||||
|         &self, |         &self, | ||||||
|         api_resource: &ApiResource, |  | ||||||
|         yaml: &Vec<serde_yaml::Value>, |         yaml: &Vec<serde_yaml::Value>, | ||||||
|         ns: Option<&str>, |         ns: Option<&str>, | ||||||
|     ) -> Result<(), Error> { |     ) -> Result<(), Error> { | ||||||
|         for y in yaml.iter() { |         for y in yaml.iter() { | ||||||
|             self.apply_yaml(api_resource, y, ns).await?; |             self.apply_yaml(y, ns).await?; | ||||||
|         } |         } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub async fn apply_yaml( |     pub async fn apply_yaml( | ||||||
|         &self, |         &self, | ||||||
|         api_resource: &ApiResource, |  | ||||||
|         yaml: &serde_yaml::Value, |         yaml: &serde_yaml::Value, | ||||||
|         ns: Option<&str>, |         ns: Option<&str>, | ||||||
|     ) -> Result<(), Error> { |     ) -> Result<(), Error> { | ||||||
|         let obj: DynamicObject = serde_yaml::from_value(yaml.clone()).expect("TODO do not unwrap"); |         let obj: DynamicObject = serde_yaml::from_value(yaml.clone()).expect("TODO do not unwrap"); | ||||||
|         let name = obj.metadata.name.as_ref().expect("YAML must have a name"); |         let name = obj.metadata.name.as_ref().expect("YAML must have a name"); | ||||||
| 
 |         let namespace = obj | ||||||
|         let namespace = match ns { |  | ||||||
|             Some(n) => n, |  | ||||||
|             None => { |  | ||||||
|                 obj |  | ||||||
|             .metadata |             .metadata | ||||||
|             .namespace |             .namespace | ||||||
|             .as_ref() |             .as_ref() | ||||||
|                     .expect("YAML must have a namespace") |             .expect("YAML must have a namespace"); | ||||||
|             }, | 
 | ||||||
|         }; |         // 4. Define the API resource type using the GVK from the object.
 | ||||||
|  |         //    The plural name 'applications' is taken from your CRD definition.
 | ||||||
|  |         error!("This only supports argocd application harcoded, very rrrong"); | ||||||
|  |         let gvk = GroupVersionKind::gvk("argoproj.io", "v1alpha1", "Application"); | ||||||
|  |         let api_resource = ApiResource::from_gvk_with_plural(&gvk, "applications"); | ||||||
| 
 | 
 | ||||||
|         // 5. Create a dynamic API client for this resource type.
 |         // 5. Create a dynamic API client for this resource type.
 | ||||||
|         let api: Api<DynamicObject> = |         let api: Api<DynamicObject> = | ||||||
|             Api::namespaced_with(self.client.clone(), namespace, api_resource); |             Api::namespaced_with(self.client.clone(), namespace, &api_resource); | ||||||
| 
 | 
 | ||||||
|         // 6. Apply the object to the cluster using Server-Side Apply.
 |         // 6. Apply the object to the cluster using Server-Side Apply.
 | ||||||
|         //    This will create the resource if it doesn't exist, or update it if it does.
 |         //    This will create the resource if it doesn't exist, or update it if it does.
 | ||||||
|  | |||||||
| @ -159,7 +159,7 @@ impl< | |||||||
|         info!("Pushed new helm chart {helm_chart}"); |         info!("Pushed new helm chart {helm_chart}"); | ||||||
| 
 | 
 | ||||||
|         error!("TODO Make building image configurable/skippable"); |         error!("TODO Make building image configurable/skippable"); | ||||||
|         let image = self.application.build_push_oci_image().await?; |         // let image = self.application.build_push_oci_image().await?;
 | ||||||
|         info!("Pushed new docker image {image}"); |         info!("Pushed new docker image {image}"); | ||||||
| 
 | 
 | ||||||
|         info!("Installing ContinuousDelivery feature"); |         info!("Installing ContinuousDelivery feature"); | ||||||
|  | |||||||
| @ -1,5 +1,4 @@ | |||||||
| use async_trait::async_trait; | use async_trait::async_trait; | ||||||
| use kube::api::{ApiResource, GroupVersionKind}; |  | ||||||
| use log::error; | use log::error; | ||||||
| use non_blank_string_rs::NonBlankString; | use non_blank_string_rs::NonBlankString; | ||||||
| use serde::Serialize; | use serde::Serialize; | ||||||
| @ -57,16 +56,9 @@ impl<T: Topology + K8sclient + HelmCommand> Interpret<T> for ArgoInterpret { | |||||||
|             .execute(inventory, topology) |             .execute(inventory, topology) | ||||||
|             .await?; |             .await?; | ||||||
| 
 | 
 | ||||||
|         let gvk = GroupVersionKind::gvk("argoproj.io", "v1alpha1", "Application"); |  | ||||||
|         let api_resource = ApiResource::from_gvk_with_plural(&gvk, "applications"); |  | ||||||
| 
 |  | ||||||
|         let k8s_client = topology.k8s_client().await?; |         let k8s_client = topology.k8s_client().await?; | ||||||
|         k8s_client |         k8s_client | ||||||
|             .apply_yaml_many( |             .apply_yaml_many(&self.argo_apps.iter().map(|a| a.to_yaml()).collect(), None) | ||||||
|                 &api_resource, |  | ||||||
|                 &self.argo_apps.iter().map(|a| a.to_yaml()).collect(), |  | ||||||
|                 None, |  | ||||||
|             ) |  | ||||||
|             .await |             .await | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
|         Ok(Outcome::success(format!( |         Ok(Outcome::success(format!( | ||||||
|  | |||||||
| @ -1,21 +1,14 @@ | |||||||
| use std::fs; | use std::fs; | ||||||
| use std::io::Read; |  | ||||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||||
| use std::process; | use std::process; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| 
 | 
 | ||||||
| use async_trait::async_trait; | use async_trait::async_trait; | ||||||
| use bollard::image::PushImageOptions; |  | ||||||
| use bollard::query_parameters::PushImageOptionsBuilder; |  | ||||||
| use bollard::{Docker, body_full}; |  | ||||||
| use dockerfile_builder::Dockerfile; | use dockerfile_builder::Dockerfile; | ||||||
| use dockerfile_builder::instruction::{CMD, COPY, ENV, EXPOSE, FROM, RUN, USER, WORKDIR}; | use dockerfile_builder::instruction::{CMD, COPY, ENV, EXPOSE, FROM, RUN, USER, WORKDIR}; | ||||||
| use dockerfile_builder::instruction_builder::CopyBuilder; | use dockerfile_builder::instruction_builder::CopyBuilder; | ||||||
| use futures_util::StreamExt; |  | ||||||
| use log::{debug, error, info}; | use log::{debug, error, info}; | ||||||
| use serde::Serialize; | use serde::Serialize; | ||||||
| use tar::Archive; |  | ||||||
| use tempfile::tempfile; |  | ||||||
| 
 | 
 | ||||||
| use crate::config::{REGISTRY_PROJECT, REGISTRY_URL}; | use crate::config::{REGISTRY_PROJECT, REGISTRY_URL}; | ||||||
| use crate::{ | use crate::{ | ||||||
| @ -115,7 +108,6 @@ impl OCICompliant for RustWebapp { | |||||||
|         // 1. Build the local image by calling the synchronous helper function.
 |         // 1. Build the local image by calling the synchronous helper function.
 | ||||||
|         let local_image_name = self.local_image_name(); |         let local_image_name = self.local_image_name(); | ||||||
|         self.build_docker_image(&local_image_name) |         self.build_docker_image(&local_image_name) | ||||||
|             .await |  | ||||||
|             .map_err(|e| format!("Failed to build Docker image: {}", e))?; |             .map_err(|e| format!("Failed to build Docker image: {}", e))?; | ||||||
|         info!( |         info!( | ||||||
|             "Successfully built local Docker image: {}", |             "Successfully built local Docker image: {}", | ||||||
| @ -125,7 +117,6 @@ impl OCICompliant for RustWebapp { | |||||||
|         let remote_image_name = self.image_name(); |         let remote_image_name = self.image_name(); | ||||||
|         // 2. Push the image to the registry.
 |         // 2. Push the image to the registry.
 | ||||||
|         self.push_docker_image(&local_image_name, &remote_image_name) |         self.push_docker_image(&local_image_name, &remote_image_name) | ||||||
|             .await |  | ||||||
|             .map_err(|e| format!("Failed to push Docker image: {}", e))?; |             .map_err(|e| format!("Failed to push Docker image: {}", e))?; | ||||||
|         info!("Successfully pushed Docker image to: {}", remote_image_name); |         info!("Successfully pushed Docker image to: {}", remote_image_name); | ||||||
| 
 | 
 | ||||||
| @ -162,68 +153,66 @@ impl RustWebapp { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Builds the Docker image using the generated Dockerfile.
 |     /// Builds the Docker image using the generated Dockerfile.
 | ||||||
|     pub async fn build_docker_image( |     pub fn build_docker_image( | ||||||
|         &self, |         &self, | ||||||
|         image_name: &str, |         image_name: &str, | ||||||
|     ) -> Result<String, Box<dyn std::error::Error>> { |     ) -> Result<String, Box<dyn std::error::Error>> { | ||||||
|         info!("Generating Dockerfile for '{}'", self.name); |         info!("Generating Dockerfile for '{}'", self.name); | ||||||
|         let _dockerfile_path = self.build_dockerfile()?; |         let dockerfile_path = self.build_dockerfile()?; | ||||||
| 
 | 
 | ||||||
|         let docker = Docker::connect_with_socket_defaults().unwrap(); |         info!( | ||||||
| 
 |             "Building Docker image with file {} from root {}", | ||||||
|         let build_image_options = bollard::query_parameters::BuildImageOptionsBuilder::default() |             dockerfile_path.to_string_lossy(), | ||||||
|             .dockerfile("Dockerfile.harmony") |             self.project_root.to_string_lossy() | ||||||
|             .t(image_name) |  | ||||||
|             .q(false) |  | ||||||
|             .version(bollard::query_parameters::BuilderVersion::BuilderV1) |  | ||||||
|             .platform("linux/x86_64"); |  | ||||||
| 
 |  | ||||||
|         let mut temp_tar_builder = tar::Builder::new(Vec::new()); |  | ||||||
|         let _ = temp_tar_builder |  | ||||||
|             .append_dir_all("", self.project_root.clone()) |  | ||||||
|             .unwrap(); |  | ||||||
|         let archive = temp_tar_builder |  | ||||||
|             .into_inner() |  | ||||||
|             .expect("couldn't finish creating tar"); |  | ||||||
|         let archived_files = Archive::new(archive.as_slice()) |  | ||||||
|             .entries() |  | ||||||
|             .unwrap() |  | ||||||
|             .map(|entry| entry.unwrap().path().unwrap().into_owned()) |  | ||||||
|             .collect::<Vec<_>>(); |  | ||||||
| 
 |  | ||||||
|         debug!("files in docker tar: {:#?}", archived_files); |  | ||||||
| 
 |  | ||||||
|         let mut image_build_stream = docker.build_image( |  | ||||||
|             build_image_options.build(), |  | ||||||
|             None, |  | ||||||
|             Some(body_full(archive.into())), |  | ||||||
|         ); |         ); | ||||||
|  |         let output = process::Command::new("docker") | ||||||
|  |             .args([ | ||||||
|  |                 "build", | ||||||
|  |                 "--file", | ||||||
|  |                 dockerfile_path.to_str().unwrap(), | ||||||
|  |                 "-t", | ||||||
|  |                 &image_name, | ||||||
|  |                 self.project_root.to_str().unwrap(), | ||||||
|  |             ]) | ||||||
|  |             .spawn()? | ||||||
|  |             .wait_with_output()?; | ||||||
| 
 | 
 | ||||||
|         while let Some(msg) = image_build_stream.next().await { |         self.check_output(&output, "Failed to build Docker image")?; | ||||||
|             println!("Message: {msg:?}"); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         Ok(image_name.to_string()) |         Ok(image_name.to_string()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Tags and pushes a Docker image to the configured remote registry.
 |     /// Tags and pushes a Docker image to the configured remote registry.
 | ||||||
|     async fn push_docker_image( |     fn push_docker_image( | ||||||
|         &self, |         &self, | ||||||
|         image_name: &str, |         image_name: &str, | ||||||
|         full_tag: &str, |         full_tag: &str, | ||||||
|     ) -> Result<String, Box<dyn std::error::Error>> { |     ) -> Result<String, Box<dyn std::error::Error>> { | ||||||
|         info!("Pushing docker image {full_tag}"); |         info!("Pushing docker image {full_tag}"); | ||||||
| 
 | 
 | ||||||
|         let docker = Docker::connect_with_socket_defaults().unwrap(); |         // Tag the image for the remote registry.
 | ||||||
|  |         let output = process::Command::new("docker") | ||||||
|  |             .args(["tag", image_name, &full_tag]) | ||||||
|  |             .spawn()? | ||||||
|  |             .wait_with_output()?; | ||||||
|  |         self.check_output(&output, "Tagging docker image failed")?; | ||||||
|  |         debug!( | ||||||
|  |             "docker tag output: stdout: {}, stderr: {}", | ||||||
|  |             String::from_utf8_lossy(&output.stdout), | ||||||
|  |             String::from_utf8_lossy(&output.stderr) | ||||||
|  |         ); | ||||||
| 
 | 
 | ||||||
|         // let push_options = PushImageOptionsBuilder::new().tag(tag);
 |         // Push the image.
 | ||||||
| 
 |         let output = process::Command::new("docker") | ||||||
|         let mut push_image_stream = |             .args(["push", &full_tag]) | ||||||
|             docker.push_image(full_tag, Some(PushImageOptionsBuilder::new().build()), None); |             .spawn()? | ||||||
| 
 |             .wait_with_output()?; | ||||||
|         while let Some(msg) = push_image_stream.next().await { |         self.check_output(&output, "Pushing docker image failed")?; | ||||||
|             println!("Message: {msg:?}"); |         debug!( | ||||||
|         } |             "docker push output: stdout: {}, stderr: {}", | ||||||
|  |             String::from_utf8_lossy(&output.stdout), | ||||||
|  |             String::from_utf8_lossy(&output.stderr) | ||||||
|  |         ); | ||||||
| 
 | 
 | ||||||
|         Ok(full_tag.to_string()) |         Ok(full_tag.to_string()) | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user