Merge "Read from new storage in aflags" into main
This commit is contained in:
@@ -1,14 +1,91 @@
|
|||||||
use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom};
|
use crate::{Flag, FlagPermission, FlagSource, FlagValue, ValuePickedFrom};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
pub struct AconfigStorageSource {}
|
pub struct AconfigStorageSource {}
|
||||||
|
|
||||||
|
use aconfig_storage_file::protos::ProtoStorageFileInfo;
|
||||||
use aconfig_storage_file::protos::ProtoStorageFiles;
|
use aconfig_storage_file::protos::ProtoStorageFiles;
|
||||||
|
use aconfig_storage_file::FlagValueAndInfoSummary;
|
||||||
|
|
||||||
static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/persistent_storage_file_records.pb";
|
static STORAGE_INFO_FILE_PATH: &str = "/metadata/aconfig/storage_records.pb";
|
||||||
|
|
||||||
|
fn read_default_values(file_info: ProtoStorageFileInfo) -> Result<HashMap<String, FlagValue>> {
|
||||||
|
let package_map =
|
||||||
|
file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?;
|
||||||
|
let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?;
|
||||||
|
let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?;
|
||||||
|
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)? {
|
||||||
|
let value = FlagValue::try_from(listed_flag.flag_value.as_str())?;
|
||||||
|
result.insert(listed_flag.package_name + &listed_flag.flag_name, value);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_next_boot_values(
|
||||||
|
listed_flags: &[FlagValueAndInfoSummary],
|
||||||
|
) -> Result<HashMap<String, FlagValue>> {
|
||||||
|
let mut result = HashMap::new();
|
||||||
|
for flag in listed_flags {
|
||||||
|
result.insert(
|
||||||
|
flag.package_name.clone() + &flag.flag_name,
|
||||||
|
FlagValue::try_from(flag.flag_value.as_str())?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reconcile(
|
||||||
|
default_values: HashMap<String, FlagValue>,
|
||||||
|
next_boot_values: HashMap<String, FlagValue>,
|
||||||
|
flags_current_boot: &[FlagValueAndInfoSummary],
|
||||||
|
container: &str,
|
||||||
|
) -> Result<Vec<Flag>> {
|
||||||
|
let mut result = Vec::new();
|
||||||
|
for listed_flag in flags_current_boot {
|
||||||
|
let default_value = default_values
|
||||||
|
.get(&(listed_flag.package_name.clone() + &listed_flag.flag_name))
|
||||||
|
.copied();
|
||||||
|
|
||||||
|
let name = listed_flag.flag_name.clone();
|
||||||
|
let package = listed_flag.package_name.clone();
|
||||||
|
let value = FlagValue::try_from(listed_flag.flag_value.as_str())?;
|
||||||
|
let container = container.to_string();
|
||||||
|
let staged_value = next_boot_values
|
||||||
|
.get(&(listed_flag.package_name.clone() + &listed_flag.flag_name))
|
||||||
|
.filter(|&v| value != *v)
|
||||||
|
.copied();
|
||||||
|
let permission = if listed_flag.is_readwrite {
|
||||||
|
FlagPermission::ReadWrite
|
||||||
|
} else {
|
||||||
|
FlagPermission::ReadOnly
|
||||||
|
};
|
||||||
|
let value_picked_from = if Some(value) == default_value {
|
||||||
|
ValuePickedFrom::Default
|
||||||
|
} else {
|
||||||
|
ValuePickedFrom::Server
|
||||||
|
};
|
||||||
|
|
||||||
|
result.push(Flag {
|
||||||
|
name,
|
||||||
|
package,
|
||||||
|
value,
|
||||||
|
container,
|
||||||
|
staged_value,
|
||||||
|
permission,
|
||||||
|
value_picked_from,
|
||||||
|
|
||||||
|
// TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.
|
||||||
|
namespace: "-".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
impl FlagSource for AconfigStorageSource {
|
impl FlagSource for AconfigStorageSource {
|
||||||
fn list_flags() -> Result<Vec<Flag>> {
|
fn list_flags() -> Result<Vec<Flag>> {
|
||||||
@@ -20,30 +97,35 @@ impl FlagSource for AconfigStorageSource {
|
|||||||
let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?;
|
let storage_file_info: ProtoStorageFiles = protobuf::Message::parse_from_bytes(&bytes)?;
|
||||||
|
|
||||||
for file_info in storage_file_info.files {
|
for file_info in storage_file_info.files {
|
||||||
let package_map =
|
let default_values = read_default_values(file_info.clone())?;
|
||||||
file_info.package_map.ok_or(anyhow!("storage file is missing package map"))?;
|
|
||||||
let flag_map = file_info.flag_map.ok_or(anyhow!("storage file is missing flag map"))?;
|
|
||||||
let flag_val = file_info.flag_val.ok_or(anyhow!("storage file is missing flag val"))?;
|
|
||||||
let container =
|
let container =
|
||||||
file_info.container.ok_or(anyhow!("storage file is missing container"))?;
|
file_info.container.ok_or(anyhow!("storage file is missing container"))?;
|
||||||
|
let package_map = format!("/metadata/aconfig/maps/{container}.package.map");
|
||||||
|
let flag_map = format!("/metadata/aconfig/maps/{container}.flag.map");
|
||||||
|
let flag_info = format!("/metadata/aconfig/boot/{container}.info");
|
||||||
|
|
||||||
for listed_flag in aconfig_storage_file::list_flags(&package_map, &flag_map, &flag_val)?
|
let flag_val_current_boot = format!("/metadata/aconfig/boot/{container}.val");
|
||||||
{
|
let flag_val_next_boot = format!("/metadata/aconfig/flags/{container}.val");
|
||||||
result.push(Flag {
|
|
||||||
name: listed_flag.flag_name,
|
|
||||||
package: listed_flag.package_name,
|
|
||||||
value: FlagValue::try_from(listed_flag.flag_value.as_str())?,
|
|
||||||
container: container.to_string(),
|
|
||||||
|
|
||||||
// TODO(b/324436145): delete namespace field once DeviceConfig isn't in CLI.
|
let flags_next_boot = aconfig_storage_file::list_flags_with_info(
|
||||||
namespace: "-".to_string(),
|
&package_map,
|
||||||
|
&flag_map,
|
||||||
|
&flag_val_next_boot,
|
||||||
|
&flag_info,
|
||||||
|
)?;
|
||||||
|
let flags_current_boot = aconfig_storage_file::list_flags_with_info(
|
||||||
|
&package_map,
|
||||||
|
&flag_map,
|
||||||
|
&flag_val_current_boot,
|
||||||
|
&flag_info,
|
||||||
|
)?;
|
||||||
|
|
||||||
// TODO(b/324436145): Populate with real values once API is available.
|
let next_boot_values = read_next_boot_values(&flags_next_boot)?;
|
||||||
staged_value: None,
|
let processed_flags =
|
||||||
permission: FlagPermission::ReadOnly,
|
reconcile(default_values, next_boot_values, &flags_current_boot, &container)?;
|
||||||
value_picked_from: ValuePickedFrom::Default,
|
|
||||||
});
|
result.extend(processed_flags);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
@@ -286,7 +286,9 @@ fn main() -> Result<()> {
|
|||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let output = match cli.command {
|
let output = match cli.command {
|
||||||
Command::List { use_new_storage: true, container } => {
|
Command::List { use_new_storage: true, container } => {
|
||||||
list(FlagSourceType::AconfigStorage, container).map(Some)
|
list(FlagSourceType::AconfigStorage, container)
|
||||||
|
.map_err(|_| anyhow!("storage may not be enabled"))
|
||||||
|
.map(Some)
|
||||||
}
|
}
|
||||||
Command::List { use_new_storage: false, container } => {
|
Command::List { use_new_storage: false, container } => {
|
||||||
list(FlagSourceType::DeviceConfig, container).map(Some)
|
list(FlagSourceType::DeviceConfig, container).map(Some)
|
||||||
|
Reference in New Issue
Block a user