Merge branch 'next/patch' of github.com:Start9Labs/start-os into next/minor

This commit is contained in:
Aiden McClelland
2023-11-16 15:11:10 -07:00
23 changed files with 200 additions and 82 deletions

2
core/Cargo.lock generated
View File

@@ -4944,7 +4944,7 @@ dependencies = [
[[package]]
name = "start-os"
version = "0.3.5"
version = "0.3.5-rev.1"
dependencies = [
"aes",
"async-compression",

View File

@@ -14,7 +14,7 @@ keywords = [
name = "start-os"
readme = "README.md"
repository = "https://github.com/Start9Labs/start-os"
version = "0.3.5"
version = "0.3.5-rev.1"
license = "MIT"
[lib]

View File

@@ -18,7 +18,7 @@ fn select_executable(name: &str) -> Option<fn()> {
match name {
#[cfg(feature = "avahi-alias")]
"avahi-alias" => Some(avahi_alias::main),
#[cfg(feature = "js_engine")]
#[cfg(feature = "js-engine")]
"start-deno" => Some(start_deno::main),
#[cfg(feature = "cli")]
"start-cli" => Some(start_cli::main),
@@ -36,24 +36,14 @@ fn select_executable(name: &str) -> Option<fn()> {
pub fn startbox() {
let args = std::env::args().take(2).collect::<Vec<_>>();
if let Some(x) = args
let executable = args
.get(0)
.and_then(|s| Path::new(&*s).file_name())
.and_then(|s| s.to_str())
.and_then(|s| select_executable(&s))
{
x()
} else if let Some(x) = args.get(1).and_then(|s| select_executable(&s)) {
.and_then(|s| s.to_str());
if let Some(x) = executable.and_then(|s| select_executable(&s)) {
x()
} else {
eprintln!(
"unknown executable: {}",
args.get(0)
.filter(|x| &**x != "startbox")
.or_else(|| args.get(1))
.map(|s| s.as_str())
.unwrap_or("N/A")
);
eprintln!("unknown executable: {}", executable.unwrap_or("N/A"));
std::process::exit(1);
}
}

View File

@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::Duration;
use helpers::NonDetachingJoinHandle;
use tokio::process::Command;
use tracing::instrument;
@@ -15,12 +16,20 @@ use crate::firmware::update_firmware;
use crate::init::STANDBY_MODE_PATH;
use crate::net::web_server::WebServer;
use crate::shutdown::Shutdown;
use crate::sound::CHIME;
use crate::sound::{BEP, CHIME};
use crate::util::Invoke;
use crate::{Error, ErrorKind, ResultExt, PLATFORM};
#[instrument(skip_all)]
async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Error> {
let song = NonDetachingJoinHandle::from(tokio::spawn(async {
loop {
BEP.play().await.unwrap();
BEP.play().await.unwrap();
tokio::time::sleep(Duration::from_secs(30)).await;
}
}));
if update_firmware().await?.0 {
return Ok(Some(Shutdown {
export_args: None,
@@ -74,6 +83,7 @@ async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Er
)
.await?;
drop(song);
tokio::time::sleep(Duration::from_secs(1)).await; // let the record state that I hate this
CHIME.play().await?;
@@ -100,8 +110,10 @@ async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Er
)
.await?;
drop(song);
tokio::time::sleep(Duration::from_secs(1)).await; // let the record state that I hate this
CHIME.play().await?;
ctx.shutdown
.subscribe()
.recv()
@@ -152,6 +164,7 @@ async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Er
}
tracing::info!("Loaded Disk");
crate::init::init(&cfg).await?;
drop(song);
}
Ok(None)

View File

@@ -22,6 +22,7 @@ use crate::net::utils::{get_iface_ipv4_addr, get_iface_ipv6_addr};
use crate::prelude::*;
use crate::s9pk::manifest::{Manifest, PackageId};
use crate::status::Status;
use crate::util::cpupower::{get_preferred_governor, Governor};
use crate::util::Version;
use crate::version::{Current, VersionT};
use crate::{ARCH, PLATFORM};
@@ -83,6 +84,7 @@ impl Database {
.join(":"),
ntp_synced: false,
zram: true,
governor: None,
},
package_data: AllPackageData::default(),
ui: serde_json::from_str(include_str!(concat!(
@@ -134,6 +136,7 @@ pub struct ServerInfo {
pub ntp_synced: bool,
#[serde(default)]
pub zram: bool,
pub governor: Option<Governor>,
}
#[derive(Debug, Deserialize, Serialize, HasModel)]

View File

@@ -20,7 +20,7 @@ use crate::middleware::auth::LOCAL_AUTH_COOKIE_PATH;
use crate::prelude::*;
use crate::sound::BEP;
use crate::util::cpupower::{
current_governor, get_available_governors, set_governor, GOVERNOR_PERFORMANCE,
current_governor, get_available_governors, get_preferred_governor, set_governor,
};
use crate::util::docker::{create_bridge_network, CONTAINER_DATADIR, CONTAINER_TOOL};
use crate::util::Invoke;
@@ -230,18 +230,6 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
|| &*server_info.version < &emver::Version::new(0, 3, 2, 0)
|| (*ARCH == "x86_64" && &*server_info.version < &emver::Version::new(0, 3, 4, 0));
let song = if should_rebuild {
Some(NonDetachingJoinHandle::from(tokio::spawn(async {
loop {
BEP.play().await.unwrap();
BEP.play().await.unwrap();
tokio::time::sleep(Duration::from_secs(60)).await;
}
})))
} else {
None
};
let log_dir = cfg.datadir().join("main/logs");
if tokio::fs::metadata(&log_dir).await.is_err() {
tokio::fs::create_dir_all(&log_dir).await?;
@@ -354,21 +342,20 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
.await?;
tracing::info!("Enabled Docker QEMU Emulation");
if current_governor()
.await?
.map(|g| &g != &GOVERNOR_PERFORMANCE)
.unwrap_or(false)
{
tracing::info!("Setting CPU Governor to \"{}\"", GOVERNOR_PERFORMANCE);
if get_available_governors()
.await?
.contains(&GOVERNOR_PERFORMANCE)
{
set_governor(&GOVERNOR_PERFORMANCE).await?;
tracing::info!("Set CPU Governor");
let governor = if let Some(governor) = &server_info.governor {
if get_available_governors().await?.contains(governor) {
Some(governor)
} else {
tracing::warn!("CPU Governor \"{}\" Not Available", GOVERNOR_PERFORMANCE)
tracing::warn!("CPU Governor \"{governor}\" Not Available");
None
}
} else {
get_preferred_governor().await?
};
if let Some(governor) = governor {
tracing::info!("Setting CPU Governor to \"{governor}\"");
set_governor(governor).await?;
tracing::info!("Set CPU Governor");
}
let mut time_not_synced = true;
@@ -447,8 +434,6 @@ pub async fn init(cfg: &RpcContextConfig) -> Result<InitResult, Error> {
}?;
}
drop(song);
tracing::info!("System initialized.");
Ok(InitResult { secret_store, db })

View File

@@ -1,5 +1,3 @@
#![recursion_limit = "256"]
pub const DEFAULT_MARKETPLACE: &str = "https://registry.start9.com";
// pub const COMMUNITY_MARKETPLACE: &str = "https://community-registry.start9.com";
pub const BUFFER_SIZE: usize = 1024;

View File

@@ -226,18 +226,18 @@ async fn test_start_deno_command() -> Result<Command, Error> {
.arg("build")
.invoke(ErrorKind::Unknown)
.await?;
if tokio::fs::metadata("target/debug/start-deno")
if tokio::fs::metadata("../target/debug/start-deno")
.await
.is_err()
{
Command::new("ln")
.arg("-rsf")
.arg("target/debug/startbox")
.arg("target/debug/start-deno")
.arg("../target/debug/startbox")
.arg("../target/debug/start-deno")
.invoke(crate::ErrorKind::Filesystem)
.await?;
}
Ok(Command::new("target/debug/start-deno"))
Ok(Command::new("../target/debug/start-deno"))
}
#[tokio::test]

View File

@@ -1,3 +1,4 @@
use std::collections::BTreeSet;
use std::fmt;
use chrono::Utc;
@@ -20,11 +21,12 @@ use crate::logs::{
};
use crate::prelude::*;
use crate::shutdown::Shutdown;
use crate::util::cpupower::{get_available_governors, set_governor, Governor};
use crate::util::serde::{display_serializable, IoFormat};
use crate::util::{display_none, Invoke};
use crate::{Error, ErrorKind, ResultExt};
#[command(subcommands(zram))]
#[command(subcommands(zram, governor))]
pub async fn experimental() -> Result<(), Error> {
Ok(())
}
@@ -85,6 +87,56 @@ pub async fn zram(#[context] ctx: RpcContext, #[arg] enable: bool) -> Result<(),
Ok(())
}
#[derive(Debug, Deserialize, Serialize)]
pub struct GovernorInfo {
current: Option<Governor>,
available: BTreeSet<Governor>,
}
fn display_governor_info(arg: GovernorInfo, matches: &ArgMatches) {
use prettytable::*;
if matches.is_present("format") {
return display_serializable(arg, matches);
}
let mut table = Table::new();
table.add_row(row![bc -> "GOVERNORS"]);
for entry in arg.available {
if Some(&entry) == arg.current.as_ref() {
table.add_row(row![g -> format!("* {entry} (current)")]);
} else {
table.add_row(row![entry]);
}
}
table.print_tty(false).unwrap();
}
#[command(display(display_governor_info))]
pub async fn governor(
#[context] ctx: RpcContext,
#[allow(unused_variables)]
#[arg(long = "format")]
format: Option<IoFormat>,
#[arg] set: Option<Governor>,
) -> Result<GovernorInfo, Error> {
let available = get_available_governors().await?;
if let Some(set) = set {
if !available.contains(&set) {
return Err(Error::new(
eyre!("Governor {set} not available"),
ErrorKind::InvalidRequest,
));
}
set_governor(&set).await?;
ctx.db
.mutate(|d| d.as_server_info_mut().as_governor_mut().ser(&Some(set)))
.await?;
}
let current = ctx.db.peek().await.as_server_info().as_governor().de()?;
Ok(GovernorInfo { current, available })
}
#[derive(Serialize, Deserialize)]
pub struct TimeInfo {
now: String,

View File

@@ -7,10 +7,20 @@ use tokio::process::Command;
use crate::prelude::*;
use crate::util::Invoke;
pub const GOVERNOR_PERFORMANCE: Governor = Governor(Cow::Borrowed("performance"));
pub const GOVERNOR_HEIRARCHY: &[Governor] = &[
Governor(Cow::Borrowed("ondemand")),
Governor(Cow::Borrowed("schedutil")),
Governor(Cow::Borrowed("conservative")),
];
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
pub struct Governor(Cow<'static, str>);
impl std::str::FromStr for Governor {
type Err = std::convert::Infallible;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(s.to_owned().into()))
}
}
impl std::fmt::Display for Governor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
@@ -29,13 +39,12 @@ impl std::borrow::Borrow<str> for Governor {
}
pub async fn get_available_governors() -> Result<BTreeSet<Governor>, Error> {
let raw = String::from_utf8(
Command::new("cpupower")
.arg("frequency-info")
.arg("-g")
.invoke(ErrorKind::CpuSettings)
.await?,
)?;
let raw = Command::new("cpupower")
.arg("frequency-info")
.arg("-g")
.invoke(ErrorKind::CpuSettings)
.await
.map_or_else(|e| Ok(e.source.to_string()), String::from_utf8)?;
let mut for_cpu: OrdMap<u32, BTreeSet<Governor>> = OrdMap::new();
let mut current_cpu = None;
for line in raw.lines() {
@@ -114,6 +123,16 @@ pub async fn current_governor() -> Result<Option<Governor>, Error> {
))
}
pub async fn get_preferred_governor() -> Result<Option<&'static Governor>, Error> {
let governors = get_available_governors().await?;
for governor in GOVERNOR_HEIRARCHY {
if governors.contains(governor) {
return Ok(Some(governor));
}
}
Ok(None)
}
pub async fn set_governor(governor: &Governor) -> Result<(), Error> {
Command::new("cpupower")
.arg("frequency-set")

View File

@@ -14,8 +14,9 @@ mod v0_3_4_2;
mod v0_3_4_3;
mod v0_3_4_4;
mod v0_3_5;
mod v0_3_5_1;
pub type Current = v0_3_5::Version;
pub type Current = v0_3_5_1::Version;
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(untagged)]
@@ -26,6 +27,7 @@ enum Version {
V0_3_4_3(Wrapper<v0_3_4_3::Version>),
V0_3_4_4(Wrapper<v0_3_4_4::Version>),
V0_3_5(Wrapper<v0_3_5::Version>),
V0_3_5_1(Wrapper<v0_3_5_1::Version>),
Other(emver::Version),
}
@@ -47,6 +49,7 @@ impl Version {
Version::V0_3_4_3(Wrapper(x)) => x.semver(),
Version::V0_3_4_4(Wrapper(x)) => x.semver(),
Version::V0_3_5(Wrapper(x)) => x.semver(),
Version::V0_3_5_1(Wrapper(x)) => x.semver(),
Version::Other(x) => x.clone(),
}
}
@@ -172,6 +175,7 @@ pub async fn init(db: &PatchDb, secrets: &PgPool) -> Result<(), Error> {
Version::V0_3_4_3(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?,
Version::V0_3_4_4(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?,
Version::V0_3_5(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?,
Version::V0_3_5_1(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?,
Version::Other(_) => {
return Err(Error::new(
eyre!("Cannot downgrade"),
@@ -208,6 +212,9 @@ mod tests {
Just(Version::V0_3_4_1(Wrapper(v0_3_4_1::Version::new()))),
Just(Version::V0_3_4_2(Wrapper(v0_3_4_2::Version::new()))),
Just(Version::V0_3_4_3(Wrapper(v0_3_4_3::Version::new()))),
Just(Version::V0_3_4_4(Wrapper(v0_3_4_4::Version::new()))),
Just(Version::V0_3_5(Wrapper(v0_3_5::Version::new()))),
Just(Version::V0_3_5_1(Wrapper(v0_3_5_1::Version::new()))),
em_version().prop_map(Version::Other),
]
}

View File

@@ -0,0 +1,32 @@
use async_trait::async_trait;
use emver::VersionRange;
use sqlx::PgPool;
use super::v0_3_4::V0_3_0_COMPAT;
use super::{v0_3_5, VersionT};
use crate::prelude::*;
const V0_3_5_1: emver::Version = emver::Version::new(0, 3, 5, 1);
#[derive(Clone, Debug)]
pub struct Version;
#[async_trait]
impl VersionT for Version {
type Previous = v0_3_5::Version;
fn new() -> Self {
Version
}
fn semver(&self) -> emver::Version {
V0_3_5_1
}
fn compat(&self) -> &'static VersionRange {
&V0_3_0_COMPAT
}
async fn up(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> {
Ok(())
}
}

View File

@@ -158,8 +158,8 @@ echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/tor.key.gpg]
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o config/archives/docker.key
echo "deb [arch=${IB_TARGET_ARCH} signed-by=/etc/apt/trusted.gpg.d/docker.key.gpg] https://download.docker.com/linux/debian ${IB_SUITE} stable" > config/archives/docker.list
curl -fsSL https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/Debian_Testing/Release.key | gpg --dearmor -o config/archives/podman.key
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/podman.key.gpg] https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/Debian_Testing/ /" > config/archives/podman.list
curl -fsSL https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/Debian_Testing/Release.key | gpg --dearmor -o config/archives/podman.key
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/podman.key.gpg] https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/unstable/Debian_Testing/ /" > config/archives/podman.list
# Dependencies

View File

@@ -4399,7 +4399,7 @@ dependencies = [
[[package]]
name = "start-os"
version = "0.3.5"
version = "0.3.5-rev.1"
dependencies = [
"aes",
"async-compression",

4
web/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "startos-ui",
"version": "0.3.5",
"version": "0.3.5.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "startos-ui",
"version": "0.3.5",
"version": "0.3.5.1",
"dependencies": {
"@angular/animations": "^14.1.0",
"@angular/common": "^14.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "startos-ui",
"version": "0.3.5",
"version": "0.3.5.1",
"author": "Start9 Labs, Inc",
"homepage": "https://start9.com/",
"scripts": {

View File

@@ -1,6 +1,6 @@
{
"name": null,
"ack-welcome": "0.3.5",
"ack-welcome": "0.3.5.1",
"marketplace": {
"selected-url": "https://registry.start9.com/",
"known-hosts": {

View File

@@ -12,6 +12,26 @@
<ion-content class="ion-padding">
<h2>This Release</h2>
<h4>0.3.5.1</h4>
<p class="note-padding">
View the complete
<a
href="https://github.com/Start9Labs/start-os/releases/tag/v0.3.5.1"
target="_blank"
noreferrer
>
release notes
</a>
for more details.
</p>
<h6>Highlights</h6>
<ul class="spaced-list">
<li>Revert perpetual performance mode for quieter fan</li>
<li>Minor bug fixes</li>
</ul>
<h2>Previous 0.3.5.x Releases</h2>
<h4>0.3.5</h4>
<p class="note-padding">
View the complete

View File

@@ -27,8 +27,8 @@
<ion-label>
<h2>{{ server.zram ? 'Disable' : 'Enable' }} zram</h2>
<p>
Enabling zram may improve server performance, especially on low RAM
devices
Zram creates compressed swap in memory, resulting in faster I/O for
low RAM devices
</p>
</ion-label>
</ion-item>

View File

@@ -65,10 +65,10 @@ export class ExperimentalFeaturesPage {
async presentAlertZram(enabled: boolean) {
const alert = await this.alertCtrl.create({
header: enabled ? 'Confirm' : 'Warning',
header: 'Confirm',
message: enabled
? 'Are you sure you want to disable zram?'
: 'zram on StartOS is experimental. It may increase performance of you server, especially if it is a low RAM device.',
? 'Are you sure you want to disable zram? It provides significant performance benefits on low RAM devices.'
: 'Enable zram? It will only make a difference on lower RAM devices.',
buttons: [
{
text: 'Cancel',
@@ -82,7 +82,6 @@ export class ExperimentalFeaturesPage {
cssClass: 'enter-click',
},
],
cssClass: enabled ? '' : 'alert-warning-message',
})
await alert.present()
}
@@ -122,7 +121,7 @@ export class ExperimentalFeaturesPage {
private async toggleZram(enabled: boolean) {
const loader = await this.loadingCtrl.create({
message: enabled ? 'Disabling zram...' : 'Enabling zram',
message: enabled ? 'Disabling zram...' : 'Enabling zram...',
})
await loader.present()

View File

@@ -21,10 +21,10 @@ export module Mock {
'shutting-down': false,
}
export const MarketplaceEos: RR.GetMarketplaceEosRes = {
version: '0.3.5',
version: '0.3.5.1',
headline: 'Our biggest release ever.',
'release-notes': {
'0.3.5': 'Some **Markdown** release _notes_ for 0.3.5',
'0.3.5.1': 'Some **Markdown** release _notes_ for 0.3.5.1',
'0.3.4.4': 'Some **Markdown** release _notes_ for 0.3.4.4',
'0.3.4.3': 'Some **Markdown** release _notes_ for 0.3.4.3',
'0.3.4.2': 'Some **Markdown** release _notes_ for 0.3.4.2',

View File

@@ -42,7 +42,7 @@ export const mockPatchData: DataModel = {
},
'server-info': {
id: 'abcdefgh',
version: '0.3.5',
version: '0.3.5.1',
'last-backup': new Date(new Date().valueOf() - 604800001).toISOString(),
'lan-address': 'https://adjective-noun.local',
'tor-address': 'https://myveryownspecialtoraddress.onion',

View File

@@ -5,8 +5,8 @@
"background_color": "#1e1e1e",
"display": "standalone",
"scope": ".",
"start_url": "/?version=035",
"id": "/?version=035",
"start_url": "/?version=0351",
"id": "/?version=0351",
"icons": [
{
"src": "assets/img/icon.png",