proxy_agent_setup/src/main.rs (300 lines of code) (raw):
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
mod args;
pub mod backup;
pub mod error;
pub mod logger;
pub mod result;
pub mod running;
pub mod setup;
#[cfg(not(windows))]
mod linux;
use clap::Parser;
use proxy_agent_shared::misc_helpers;
use proxy_agent_shared::service;
use std::process;
use std::time::Duration;
use std::{fs, path::PathBuf};
#[cfg(windows)]
const SERVICE_NAME: &str = "GuestProxyAgent";
const SERVICE_DISPLAY_NAME: &str = "Microsoft Azure Guest Proxy Agent";
#[cfg(not(windows))]
const SERVICE_NAME: &str = "azure-proxy-agent";
#[tokio::main]
async fn main() {
logger::init_logger();
let cli = args::Cli::parse();
logger::write(format!(
"\r\n\r\n============== ProxyAgent Setup Tool ({}) is starting with args: {} ==============",
misc_helpers::get_current_version(),
cli
));
match cli.command {
args::Command::Backup => {
backup_proxy_agent();
}
args::Command::Restore { delete_backup } => {
if !check_backup_exists() {
logger::write("Backup check failed, skip the restore operation.".to_string());
return;
}
stop_service().await;
let proxy_agent_target_folder = restore_proxy_agent();
setup_service(
proxy_agent_target_folder,
backup::proxy_agent_backup_folder(),
)
.await;
if delete_backup {
delete_backup_folder();
}
}
args::Command::Uninstall { uninstall_mode } => {
let proxy_agent_running_folder = uninstall_service().await;
if uninstall_mode == args::UninstallMode::Package {
delete_package(proxy_agent_running_folder);
}
}
args::Command::Purge => {
delete_backup_folder();
}
args::Command::Install => {
stop_service().await;
let proxy_agent_target_folder = copy_proxy_agent();
setup_service(
proxy_agent_target_folder,
misc_helpers::get_current_exe_dir(),
)
.await;
}
}
}
fn copy_proxy_agent() -> PathBuf {
let src_folder = setup::proxy_agent_folder_in_setup();
let dst_folder = running::proxy_agent_version_target_folder(&setup::proxy_agent_exe_in_setup());
#[cfg(windows)]
{
copy_proxy_agent_files(src_folder, dst_folder.to_path_buf());
}
#[cfg(not(windows))]
{
linux::copy_files(src_folder);
}
dst_folder
}
fn backup_proxy_agent() {
#[cfg(windows)]
{
copy_proxy_agent_files(
running::proxy_agent_running_folder(SERVICE_NAME),
backup::proxy_agent_backup_package_folder(),
);
}
#[cfg(not(windows))]
{
linux::backup_files();
}
}
fn restore_proxy_agent() -> PathBuf {
let src_folder = backup::proxy_agent_backup_package_folder();
let dst_folder =
running::proxy_agent_version_target_folder(&setup::proxy_agent_exe_path(&src_folder));
#[cfg(windows)]
{
copy_proxy_agent_files(src_folder, dst_folder.to_path_buf());
}
#[cfg(not(windows))]
{
linux::copy_files(src_folder);
}
dst_folder
}
#[cfg(windows)]
fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) {
match misc_helpers::try_create_folder(&dst_folder) {
Ok(_) => {}
Err(e) => {
logger::write(format!(
"Failed to create folder {:?}, error: {:?}",
dst_folder, e
));
}
}
match misc_helpers::get_files(&src_folder) {
Ok(files) => {
for file in files {
let file_name = misc_helpers::get_file_name(&file);
let dst_file = dst_folder.join(&file_name);
match fs::copy(&file, &dst_file) {
Ok(_) => {
logger::write(format!("Copied {:?} to {:?}", file, dst_file));
}
Err(e) => {
logger::write(format!(
"Failed to copy {:?} to {:?}, error: {:?}",
file, dst_file, e
));
}
}
}
}
Err(e) => {
logger::write(format!(
"Failed to get files from {:?}, error: {:?}",
src_folder, e
));
}
}
}
async fn stop_service() {
match service::stop_service(SERVICE_NAME).await {
Ok(_) => {
logger::write(format!("Stopped service {} successfully", SERVICE_NAME));
}
Err(e) => {
logger::write(format!(
"Stopped service {} failed, error: {:?}",
SERVICE_NAME, e
));
}
}
}
async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folder_path: PathBuf) {
#[cfg(windows)]
{
// delete the existing proxy agent service folder
let proxy_agent_running_folder = running::proxy_agent_running_folder(SERVICE_NAME);
if proxy_agent_running_folder.exists()
&& proxy_agent_running_folder != proxy_agent_target_folder
{
delete_folder(proxy_agent_running_folder);
}
}
#[cfg(not(windows))]
{
match linux::setup_service(SERVICE_NAME, _service_config_folder_path) {
Ok(_) => {
logger::write(format!("Setup service {} successfully", SERVICE_NAME));
}
Err(e) => {
logger::write(format!(
"Setup service {} failed, error: {:?}",
SERVICE_NAME, e
));
process::exit(1);
}
}
}
match service::install_service(
SERVICE_NAME,
SERVICE_DISPLAY_NAME,
vec!["EbpfCore", "NetEbpfExt"],
setup::proxy_agent_exe_path(&proxy_agent_target_folder),
) {
Ok(_) => {
logger::write(format!("Install service {} successfully", SERVICE_NAME));
}
Err(e) => {
logger::write(format!(
"Install service {} failed, error: {:?}",
SERVICE_NAME, e
));
process::exit(1);
}
}
#[cfg(windows)]
{
// check if eBPF setup script exists, if exist then try launch the eBPF setup scripts
let ebpf_setup_script_file = setup::ebpf_setup_script_file();
if ebpf_setup_script_file.exists() && ebpf_setup_script_file.is_file() {
let setup_script_file_str = misc_helpers::path_to_string(&ebpf_setup_script_file);
match misc_helpers::execute_command(
"powershell.exe",
vec![
"-ExecutionPolicy",
"Bypass",
"-File",
&setup_script_file_str,
],
1,
) {
Ok(output) => {
logger::write(format!(
"ebpf_setup: invoked script file '{}' with result: '{}'.",
setup_script_file_str,
output.message()
));
}
Err(e) => {
logger::write(format!(
"ebpf_setup: failed to invoke script file '{}', error: '{:?}'.",
setup_script_file_str, e
));
}
}
}
}
match service::start_service(SERVICE_NAME, 5, Duration::from_secs(15)).await {
Ok(_) => {
logger::write(format!("Service {} start successfully", SERVICE_NAME));
}
Err(e) => {
logger::write(format!(
"Service {} start failed, error: {:?}",
SERVICE_NAME, e
));
process::exit(1);
}
}
logger::write(format!("Service {} start successfully", SERVICE_NAME));
}
fn check_backup_exists() -> bool {
let proxy_agent_exe = setup::proxy_agent_exe_path(&backup::proxy_agent_backup_package_folder());
if !proxy_agent_exe.exists() {
logger::write(format!(
"GuestProxyAgent ({:?}) does not exists.",
proxy_agent_exe
));
return false;
}
true
}
async fn uninstall_service() -> PathBuf {
let proxy_agent_running_folder = running::proxy_agent_running_folder(SERVICE_NAME);
match service::stop_and_delete_service(SERVICE_NAME).await {
Ok(_) => {
logger::write(format!("Uninstall service {} successfully", SERVICE_NAME));
}
Err(e) => {
logger::write(format!(
"Uninstall service {} failed, error: {:?}",
SERVICE_NAME, e
));
process::exit(1);
}
}
proxy_agent_running_folder
}
fn delete_package(_proxy_agent_running_folder: PathBuf) {
#[cfg(windows)]
{
delete_folder(_proxy_agent_running_folder);
}
#[cfg(not(windows))]
{
linux::delete_files();
}
}
fn delete_folder(folder_to_be_delete: PathBuf) {
match fs::remove_dir_all(&folder_to_be_delete) {
Ok(_) => {
logger::write(format!("Deleted folder {:?}", folder_to_be_delete));
}
Err(e) => {
logger::write(format!(
"Failed to delete folder {:?}, error: {:?}",
folder_to_be_delete, e
));
}
}
}
fn delete_backup_folder() {
let backup_folder = backup::proxy_agent_backup_folder();
delete_folder(backup_folder);
}