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