Skip to main content

flowey_lib_common/
install_azure_cli.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Globally install the Azure CLI (`az`)
5
6use flowey::node::prelude::*;
7
8flowey_config! {
9    /// Config for the install_azure_cli node.
10    pub struct Config {
11        /// Which version of azure-cli to install (e.g: 2.57.0)
12        pub version: Option<String>,
13        /// Automatically install all required azure-cli tools and components.
14        ///
15        /// This must be set to true/false when running locally.
16        pub auto_install: Option<bool>,
17    }
18}
19
20flowey_request! {
21    pub enum Request {
22        /// Get a path to `az`
23        GetAzureCli(WriteVar<PathBuf>),
24    }
25}
26
27new_flow_node_with_config!(struct Node);
28
29impl FlowNodeWithConfig for Node {
30    type Request = Request;
31    type Config = Config;
32
33    fn imports(_ctx: &mut ImportCtx<'_>) {}
34
35    fn emit(
36        config: Config,
37        requests: Vec<Self::Request>,
38        ctx: &mut NodeCtx<'_>,
39    ) -> anyhow::Result<()> {
40        let mut get_az_cli = Vec::new();
41
42        for req in requests {
43            match req {
44                Request::GetAzureCli(v) => get_az_cli.push(v),
45            }
46        }
47
48        // don't require specifying a Version if no one requested az to
49        // be installed
50        if get_az_cli.is_empty() {
51            return Ok(());
52        }
53
54        let auto_install = config.auto_install;
55        let version = config
56            .version
57            .ok_or(anyhow::anyhow!("missing config: version"))?;
58        let get_az_cli = get_az_cli;
59
60        // -- end of req processing -- //
61
62        let check_az_install = {
63            |_rt: &RustRuntimeServices<'_>| -> anyhow::Result<PathBuf> {
64                let Ok(path) = which::which("az") else {
65                    anyhow::bail!("did not find `az` on $PATH");
66                };
67
68                // FUTURE: should also perform version checks...
69                anyhow::Ok(path)
70            }
71        };
72
73        match ctx.backend() {
74            FlowBackend::Local => {
75                let auto_install = auto_install
76                    .ok_or(anyhow::anyhow!("Missing essential request: AutoInstall"))?;
77
78                if auto_install {
79                    ctx.emit_rust_step("installing azure-cli", |ctx| {
80                        let get_az_cli = get_az_cli.claim(ctx);
81                        move |rt| {
82                            log::warn!("automatic azure-cli installation is not supported yet!");
83                            log::warn!(
84                                "follow the guide, and manually ensure you have azure-cli installed"
85                            );
86                            log::warn!("  ensure you have azure-cli version {version} installed");
87                            log::warn!("press <enter> to continue");
88                            let _ = std::io::stdin().read_line(&mut String::new());
89
90                            let path = check_az_install(rt)?;
91                            rt.write_all(get_az_cli, &path);
92                            Ok(())
93                        }
94                    })
95                } else {
96                    ctx.emit_rust_step("detecting azure-cli install", |ctx| {
97                        let get_az_cli = get_az_cli.claim(ctx);
98                        move |rt| {
99                            let path = check_az_install(rt)?;
100                            rt.write_all(get_az_cli, &path);
101                            Ok(())
102                        }
103                    })
104                }
105            }
106            FlowBackend::Ado => {
107                if !auto_install.unwrap_or(true) {
108                    anyhow::bail!("AutoInstall must be `true` when running on ADO")
109                }
110
111                // FUTURE: don't assume that all ADO workers come with azure-cli
112                // pre-installed.
113                ctx.emit_rust_step("detecting azure-cli install", |ctx| {
114                    let get_az_cli = get_az_cli.claim(ctx);
115                    move |rt| {
116                        let path = check_az_install(rt)?;
117                        rt.write_all(get_az_cli, &path);
118                        Ok(())
119                    }
120                })
121            }
122            FlowBackend::Github => {
123                if !auto_install.unwrap_or(true) {
124                    anyhow::bail!("AutoInstall must be `true` when running on Github Actions")
125                }
126
127                ctx.emit_rust_step("installing azure-cli", |ctx| {
128                    let get_az_cli = get_az_cli.claim(ctx);
129                    move |rt| {
130                        if let Ok(path) = check_az_install(rt) {
131                            rt.write_all(get_az_cli, &path);
132                            return Ok(());
133                        }
134                        match rt.platform() {
135                            FlowPlatform::Windows => {
136                                let az_dir = rt.sh.current_dir().join("az");
137                                rt.sh.create_dir(&az_dir)?;
138                                rt.sh.change_dir(&az_dir);
139                                flowey::shell_cmd!(
140                                    rt,
141                                    "curl --fail -L https://aka.ms/installazurecliwindowszipx64 -o az.zip"
142                                )
143                                .run()?;
144                                flowey::shell_cmd!(rt, "tar -xf az.zip").run()?;
145                                rt.write_all(get_az_cli, &az_dir.join("bin\\az.cmd"));
146                            }
147                            FlowPlatform::Linux(_) => {
148                                flowey::shell_cmd!(
149                                    rt,
150                                    "curl --fail -sL https://aka.ms/InstallAzureCLIDeb -o InstallAzureCLIDeb.sh"
151                                )
152                                .run()?;
153                                flowey::shell_cmd!(rt, "chmod +x ./InstallAzureCLIDeb.sh").run()?;
154                                flowey::shell_cmd!(rt, "sudo ./InstallAzureCLIDeb.sh").run()?;
155                                let path = check_az_install(rt)?;
156                                rt.write_all(get_az_cli, &path);
157                            }
158                            platform => anyhow::bail!("unsupported platform {platform}"),
159                        };
160
161                        Ok(())
162                    }
163                })
164            }
165        };
166
167        Ok(())
168    }
169}