Skip to main content

mz_orchestratord/
lib.rs

1// Copyright Materialize, Inc. and contributors. All rights reserved.
2//
3// Use of this software is governed by the Business Source License
4// included in the LICENSE file.
5//
6// As of the Change Date specified in that file, in accordance with
7// the Business Source License, use of this software will be governed
8// by the Apache License, Version 2.0.
9
10use std::fmt::Display;
11
12pub mod controller;
13pub mod gcp_node_upgrade;
14pub mod k8s;
15pub mod metrics;
16pub mod tls;
17pub mod webhook;
18
19#[derive(Debug, thiserror::Error)]
20pub enum Error {
21    Anyhow(#[from] anyhow::Error),
22    Kube(#[from] kube::Error),
23    Reqwest(#[from] reqwest::Error),
24}
25
26impl Display for Error {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        match self {
29            Self::Anyhow(e) => write!(f, "{e}"),
30            Self::Kube(e) => write!(f, "{e}"),
31            Self::Reqwest(e) => write!(f, "{e}"),
32        }
33    }
34}
35
36/// Extracts the tag from an OCI image reference, correctly ignoring
37/// registry-host ports (`gcr.io:443/...`) and `@sha256:` digests.
38pub fn parse_image_tag(image_ref: &str) -> Option<&str> {
39    let before_digest = image_ref.split('@').next().unwrap_or(image_ref);
40    let name_part = before_digest
41        .rsplit_once('/')
42        .map_or(before_digest, |(_, n)| n);
43    name_part.rsplit_once(':').map(|(_, tag)| tag)
44}
45
46pub fn matching_image_from_environmentd_image_ref(
47    environmentd_image_ref: &str,
48    image_name: &str,
49    image_tag: Option<&str>,
50) -> String {
51    let namespace = environmentd_image_ref
52        .rsplit_once('/')
53        .unwrap_or(("materialize", ""))
54        .0;
55    let tag = image_tag
56        .or_else(|| parse_image_tag(environmentd_image_ref))
57        .unwrap_or("latest");
58    format!("{namespace}/{image_name}:{tag}")
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[mz_ore::test]
66    fn test_parse_image_tag() {
67        for (input, expected) in [
68            ("materialize/environmentd:v0.27.0", Some("v0.27.0")),
69            ("materialize/environmentd", None),
70            (
71                "gcr.io:443/materialize/environmentd:v0.27.0",
72                Some("v0.27.0"),
73            ),
74            ("gcr.io:443/materialize/environmentd", None),
75            ("pkg.dev/proj/repo/env@sha256:deadbeef", None),
76            ("pkg.dev/proj/repo/env:v1.0@sha256:deadbeef", Some("v1.0")),
77            ("environmentd:latest", Some("latest")),
78            ("environmentd", None),
79        ] {
80            assert_eq!(parse_image_tag(input), expected, "input: {input}");
81        }
82    }
83
84    #[mz_ore::test]
85    fn test_matching_image() {
86        let f = matching_image_from_environmentd_image_ref;
87        assert_eq!(
88            f("materialize/environmentd:v0.27.0", "console", None),
89            "materialize/console:v0.27.0"
90        );
91        assert_eq!(
92            f(
93                "materialize/environmentd:v0.27.0",
94                "console",
95                Some("custom")
96            ),
97            "materialize/console:custom"
98        );
99        assert_eq!(
100            f("gcr.io:443/materialize/environmentd", "clusterd", None),
101            "gcr.io:443/materialize/clusterd:latest"
102        );
103        assert_eq!(
104            f("pkg.dev/proj/repo/env@sha256:deadbeef", "console", None),
105            "pkg.dev/proj/repo/console:latest"
106        );
107        assert_eq!(
108            f("environmentd", "console", None),
109            "materialize/console:latest"
110        );
111    }
112}