Add deployment.keys.<name>.uploadAt

This mirrors the functionality recently added in morph and allows
for the uploading of keys after system profile activation.

Fixes #10.
This commit is contained in:
Zhaofeng Li 2021-08-24 23:25:46 -07:00
parent e788fb02d0
commit 24339bcca7
4 changed files with 62 additions and 6 deletions

View file

@ -258,6 +258,8 @@ For example, to deploy DNS-01 credentials for use with `security.acme`:
user = "acme"; # Default: root user = "acme"; # Default: root
group = "nginx"; # Default: root group = "nginx"; # Default: root
permissions = "0640"; # Default: 0600 permissions = "0640"; # Default: 0600
uploadAt = "pre-activation"; # Default: pre-activation, Alternative: post-activation
}; };
# Rest of configuration... # Rest of configuration...
}; };

View file

@ -6,6 +6,7 @@ use futures::future::join_all;
use tokio::sync::{Mutex, Semaphore}; use tokio::sync::{Mutex, Semaphore};
use super::{Hive, Host, CopyOptions, NodeConfig, Profile, StoreDerivation, ProfileMap, host}; use super::{Hive, Host, CopyOptions, NodeConfig, Profile, StoreDerivation, ProfileMap, host};
use super::key::{Key, UploadAt};
use crate::progress::{Progress, TaskProgress, OutputStyle}; use crate::progress::{Progress, TaskProgress, OutputStyle};
/// Amount of RAM reserved for the system, in MB. /// Amount of RAM reserved for the system, in MB.
@ -523,10 +524,20 @@ impl Deployment {
} }
} }
if self.options.upload_keys && !target.config.keys.is_empty() { let pre_activation_keys = target.config.keys.iter()
.filter(|(_, v)| v.upload_at() == UploadAt::PreActivation)
.map(|(k, v)| (k.clone(), v.clone()))
.collect::<HashMap<String, Key>>();
let post_activation_keys = target.config.keys.iter()
.filter(|(_, v)| v.upload_at() == UploadAt::PostActivation)
.map(|(k, v)| (k.clone(), v.clone()))
.collect::<HashMap<String, Key>>();
if self.options.upload_keys && !pre_activation_keys.is_empty() {
bar.log("Uploading keys..."); bar.log("Uploading keys...");
if let Err(e) = target.host.upload_keys(&target.config.keys).await { if let Err(e) = target.host.upload_keys(&pre_activation_keys).await {
bar.failure_err(&e); bar.failure_err(&e);
let mut results = self.results.lock().await; let mut results = self.results.lock().await;
@ -546,6 +557,21 @@ impl Deployment {
match target.host.deploy(&profile, self.goal, copy_options).await { match target.host.deploy(&profile, self.goal, copy_options).await {
Ok(_) => { Ok(_) => {
// FIXME: This is ugly
if self.options.upload_keys && !post_activation_keys.is_empty() {
bar.log("Uploading keys (post-activation)...");
if let Err(e) = target.host.upload_keys(&post_activation_keys).await {
bar.failure_err(&e);
let mut results = self.results.lock().await;
let stage = Stage::Apply(name.to_string());
let logs = target.host.dump_logs().await.map(|s| s.to_string());
results.push(DeploymentResult::failure(stage, logs));
return;
}
}
bar.success(self.goal.success_str().unwrap()); bar.success(self.goal.success_str().unwrap());
let mut results = self.results.lock().await; let mut results = self.results.lock().await;

View file

@ -241,6 +241,18 @@ let
default = "0600"; default = "0600";
type = types.str; type = types.str;
}; };
uploadAt = lib.mkOption {
description = ''
When to upload the keys.
- pre-activation (default): Upload the keys before activating the new system profile.
- post-activation: Upload the keys after successfully activating the new system profile.
For `colmena upload-keys`, all keys are uploaded at the same time regardless of the configuration here.
'';
default = "pre-activation";
type = types.enum [ "pre-activation" "post-activation" ];
};
}; };
}; };

View file

@ -75,6 +75,18 @@ struct KeySources {
file: Option<PathBuf>, file: Option<PathBuf>,
} }
/// When to upload a given key.
#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
pub enum UploadAt {
/// Before activating the system profile.
#[serde(rename = "pre-activation")]
PreActivation,
/// After successfully activating the system profile.
#[serde(rename = "post-activation")]
PostActivation,
}
#[derive(Debug, Clone, Validate, Serialize, Deserialize)] #[derive(Debug, Clone, Validate, Serialize, Deserialize)]
pub struct Key { pub struct Key {
#[serde(flatten)] #[serde(flatten)]
@ -91,6 +103,9 @@ pub struct Key {
group: String, group: String,
permissions: String, permissions: String,
#[serde(rename = "uploadAt")]
upload_at: UploadAt,
} }
impl Key { impl Key {
@ -133,6 +148,7 @@ impl Key {
pub fn user(&self) -> &str { &self.user } pub fn user(&self) -> &str { &self.user }
pub fn group(&self) -> &str { &self.group } pub fn group(&self) -> &str { &self.group }
pub fn permissions(&self) -> &str { &self.permissions } pub fn permissions(&self) -> &str { &self.permissions }
pub fn upload_at(&self) -> UploadAt { self.upload_at }
} }
fn validate_unix_name(name: &str) -> Result<(), ValidationError> { fn validate_unix_name(name: &str) -> Result<(), ValidationError> {