1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
use super::{vault::Vault, Manifest, Region, Result}; /// Type of primary workload that is associated with the Manifest #[derive(Serialize, Deserialize, Clone, Debug)] pub enum PrimaryWorkload { Deployment, Statefulset, } impl ToString for PrimaryWorkload { fn to_string(&self) -> String { format!("{:?}", self).to_lowercase() } } impl Default for PrimaryWorkload { fn default() -> Self { Self::Deployment } } /// Various internal states a manifest can exist in depending on resolution. /// /// This only matters within shipcat and is used to optimize speed of accessors. #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub enum ManifestState { /// A completed manifest /// /// The version that is fully ready to pass to `helm template`, i.e.: /// - region overrides accounted for /// - evars are templated /// - secrets are available /// - configs inlined and templated with secrets /// /// This is the `shipcat values -s` equivalent of a manifest. /// /// A `Base` Manifest can become a `Completed` Manifest by: /// - templating evars /// - evaluating secrets /// - templating configs Completed, /// A stubbed manifest /// /// Indistinguishable from a `Completed` manifest except from secrets: /// - secrets populated with garbage values (not resolved from vault) /// - configs templated with garbage secret values /// - evars templated with garbage secret values /// /// This is the `shipcat values` equivalent of a manifest. Stubbed, /// The Base manifest /// /// A state that is upgradeable to a completed one, contains all the pieces, /// but does not have any secrets. This form is used internally in the cli, /// as well as in the cluster as the canonical CRD state. /// /// Major features: /// - region overrides accounted for /// - templates (configs + evars) left in template form /// - secrets unresolved /// /// This is the CRD equivalent of a manifest. /// It's important that the CRD equivalent abstracts away config files, but not secrets. /// Thus files have to be read, and not templated for this, then shipped off to kube. Base, } /// Default is the feature-specified base type to force constructors into chosing. /// /// This relies on serde default to populate on deserialize from disk/crd. impl Default for ManifestState { fn default() -> Self { ManifestState::Base } } /// This library defines the way to upgrade a manifest from Base /// but each backend has to implement its own way of: /// - listing services from its backing /// - creating a base manifest from its backing impl Manifest { /// Upgrade a `Base` manifest to either a Complete or a Stubbed one async fn upgrade(mut self, reg: &Region, state: ManifestState) -> Result<Self> { assert_eq!(self.state, ManifestState::Base); // sanity let v = match state { ManifestState::Completed => Vault::regional(®.vault)?, ManifestState::Stubbed => Vault::mocked(®.vault)?, _ => bail!("Can only upgrade a Base manifest to Completed or Stubbed"), }; // replace one-off templates in evar strings with values // note that this happens before secrets because: // secrets may be injected at this step from the Region self.template_evars(reg)?; // secrets before configs (.j2 template files use raw secret values) self.secrets(&v, ®.vault).await?; // templates last self.template_configs(reg)?; self.state = state; Ok(self) } /// Complete a Base manifest with stub secrets pub async fn stub(self, reg: &Region) -> Result<Self> { self.upgrade(reg, ManifestState::Stubbed).await } /// Complete a Base manifest with actual secrets pub async fn complete(self, reg: &Region) -> Result<Self> { self.upgrade(reg, ManifestState::Completed).await } /// Check to see we are using the right types of manifests internally pub fn is_base(&self) -> bool { self.state == ManifestState::Base } } /// Various states a Config can exist in depending on resolution. /// /// Within shipcat, this is used to optimize speed of accessors. #[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] pub enum ConfigState { /// A filtered config for a specific region, with resolved secrets Filtered, /// Region-independent, unresolved secrets /// /// Just like Base - but for all regions UnionisedBase, /// A config with a single region entry with blank secrets /// /// Same as what's on disk, secrets unresolved, but only one region. /// This is the CRD equivalent. Base, /// The full config as read from disk. Secrets unresolved #[cfg(feature = "filesystem")] File, } /// Default is the feature-specified base type to force constructors into chosing. /// /// This relies on serde default to populate on deserialize from disk/crd. impl Default for ConfigState { #[cfg(feature = "filesystem")] fn default() -> Self { ConfigState::File } #[cfg(not(feature = "filesystem"))] fn default() -> Self { ConfigState::Base } }