Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use notification system for OS updates #2670

Merged
merged 10 commits into from
Dec 2, 2024
5 changes: 4 additions & 1 deletion core/startos/src/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ use serde::{Deserialize, Serialize};
use tracing::instrument;
use ts_rs::TS;

use crate::backup::BackupReport;
use crate::context::{CliContext, RpcContext};
use crate::db::model::DatabaseModel;
use crate::prelude::*;
use crate::util::serde::HandlerExtSerde;
use crate::{backup::BackupReport, db::model::Database};

// #[command(subcommands(list, delete, delete_before, create))]
pub fn notification<C: Context>() -> ParentHandler<C> {
Expand Down Expand Up @@ -285,6 +285,9 @@ impl NotificationType for () {
impl NotificationType for BackupReport {
const CODE: u32 = 1;
}
impl NotificationType for String {
const CODE: u32 = 2;
}

#[instrument(skip(subtype, db))]
pub fn notify<T: NotificationType>(
Expand Down
83 changes: 83 additions & 0 deletions core/startos/src/version/update_details/v0_3_6.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# StartOS v0.3.6

## Warning

Previous backups are incompatible with v0.3.6. It is strongly recommended that you (1) immediately update all services, then (2) create a fresh backup. See the [backups](#improved-backups) section below for more details.

## Summary

Servers are not toys. They are a critical component of the computing paradigm, and their failure can be catastrophic, resulting in downtime or loss of data. From the beginning, Start9 has taken a "security and reliability first" approach to the development of StartOS, favoring soundness over speed and prioritizing essential features such as encrypted network connections, simple backups, and a reliable container runtime over nice-to-haves like custom theming and more apps.

Start9 is paving new ground with StartOS, trying to achieve what most developers and IT professionals thought impossible; namely, giving a normal person the same independent control over their data and communications as an experienced Linux sysadmin.

A consequence of our principled approach to development, combined with the difficulty of our endeavor, is that (1) mistakes will be made and (2) they must be corrected. That means a willingness to discard bad ideas and broken parts, and if absolutely necessary, to nuke everything and start over from scratch. We did this in 2020 with StartOS v0.2.0, again in 2022 with StartOS v0.3.0, and now in 2024 with StartOS v0.3.6.

StartOS v0.3.6 is a complete rewrite of the OS internals (everything you don't see). Almost nothing survived. After nearly five years of building StartOS, we believe that we have finally arrived at the correct architecture and foundation, and that no additional rewrites will be necessary for StartOS to deliver on its promise.

## Changelog

- [Switch to lxc-based container runtime](#lxc)
- [Update s9pk archive format](#new-s9pk-archive-format)
- [Improve config](#better-config)
- [Unify Actions](#unify-actions)
- [Use squashfs images for OS updates](#squashfs-updates)
- [Introduce Typescript package API and SDK](#typescript-package-api-and-sdk)
- [Remove Postgresql](#remove-postgressql)
- [Implement detailed progress reporting](#progress-reporting)
- [Improve registry protocol](#registry-protocol)
- [Replace unique .local URLs with unique ports](#lan-port-forwarding)
- [Use start-fs Fuse module for improved backups](#improved-backups)
- [Switch to Exver for versioning](#Exver)
- [Support clearnet hosting via start-cli](#clearnet)

### LXC

StartOS now uses a nested container paradigm based on LXC for the outer container, and using linux namespaces for the inner lite containers. This replaces both Docker and Podman.

### S9PK archive format

The S9PK archive format has been overhauled to allow for signature verification of partial downloads, and allow direct mounting of container images without unpacking the s9pk.

### Better config

Expanded support for input types and a new UI makes configuring services easier and more powerful.

### Actions

Actions take arbitrary form input _and_ return arbitrary responses, thus satisfying the needs of both Config and Properties, which will be removed in a future release. This gives packages developers the ability to break up Config and Properties into smaller, more specific formats, or to exclude them entirely without polluting the UI.

### Squashfs updates

StartOS now uses squashfs images to represent OS updates. This allows for better update verification, and improved reliability over rsync updates.

### Typescript package API and SDK

StartOS now exposes a Typescript API. Package developers can take advantage in a simple, typesafe way using the new start-sdk. A barebones StartOS package (s9pk) can be produced in minutes with minimal knowledge or skill. More advanced developers can use the SDK to create highly customized user experiences with their service.

### Remove PostgresSQL

StartOS itself has miniscule data persistence needs. PostgresSQL was overkill and has been removed in favor of lightweight PatchDB.

### Progress reporting

A new progress reporting API enabled package developers to create unique phases and provide real-time progress reporting for actions such as installing, updating, or backing up a service.

### Registry protocol

The new registry protocol bifurcates package indexing (listing/validating) and package hosting (downloading). Registries are now simple indexes of packages that reference binaries hosted in arbitrary locations, locally or externally. For example, when someone visits the Start9 Registry, the currated list of packages comes from Start9. But when someone installs a listed service, the package binary is being downloaded from Github. The registry also valides the binary. This makes it much easier to host a custom registry, since it is just a currated list of services tat reference package binaries hosted on Github or elsewhere.

### LAN port forwarding

Perhaps the biggest complaint with prior version of StartOS was use of unique .local URLs for service interfaces. This has been corrected. Service interfaces are now available on unique ports, allowing for non-http traffic on the LAN as well as remote access via VPN.

### Improved Backups

The new start-fs fuse module unifies file system expectations for various platforms, enabling more reliable backups. The new system also defaults to using rsync differential backups instead of incremental backups, which is faster and saves on disk space by also deleting from the backup files that were deleted from the server.

### Exver

StartOS now uses Extended Versioning (Exver), which consists of three parts, separated by semicolons: (1) a Semver-compliant upstream version, (2) a Semver-compliant wrapper version, and (3) an optional "flavor" prefix. Flavors can be thought of as alternative implementations of services, where a user would only want one or the other installed, and data can feasibly be migrating beetween the two. Another common characteristic of flavors is that they satisfy the same API requirement of dependents, though this is not strictly necessary. A valid Exver looks something like this: `#knots:28.0.:1.0-beta.1`. This would translate to "the first beta release of StartOS wrapper version 1.0 of Bitcoin Knots version 27.0".

### Clearnet

It is now possible, and quite easy, to expose specific services interfaces to the public Internet on a standard domain using start-cli. This functionality will be expanded upon and moved into the StartOS UI in a future release.
30 changes: 24 additions & 6 deletions core/startos/src/version/v0_3_6_alpha_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use exver::{PreReleaseSegment, VersionRange};

use super::v0_3_5::V0_3_0_COMPAT;
use super::{v0_3_6_alpha_5, VersionT};
use crate::notifications::{notify, NotificationLevel};
use crate::prelude::*;

lazy_static::lazy_static! {
Expand All @@ -11,23 +12,40 @@ lazy_static::lazy_static! {
);
}

#[derive(Clone, Copy, Debug, Default)]
#[derive(Default, Clone, Copy, Debug)]
pub struct Version;

impl VersionT for Version {
type Previous = v0_3_6_alpha_5::Version;
type PreUpRes = ();

async fn pre_up(self) -> Result<Self::PreUpRes, Error> {
Ok(())
}
fn semver(self) -> exver::Version {
V0_3_6_alpha_6.clone()
}
fn compat(self) -> &'static VersionRange {
&V0_3_0_COMPAT
}
fn up(self, _db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> {
async fn pre_up(self) -> Result<Self::PreUpRes, Error> {
Ok(())
}
fn up(self, db: &mut Value, _: Self::PreUpRes) -> Result<(), Error> {
Ok(())
}
async fn post_up<'a>(self, ctx: &'a crate::context::RpcContext) -> Result<(), Error> {
let message_update = include_str!("update_details/v0_3_6.md").to_string();

ctx.db
.mutate(|db| {
notify(
db,
None,
NotificationLevel::Success,
"Welcome to StartOS 0.3.6!".to_string(),
"Click \"View Details\" to learn all about the new version".to_string(),
message_update,
)?;
Ok(())
})
.await?;
Ok(())
}
fn down(self, _db: &mut Value) -> Result<(), Error> {
Expand Down
2 changes: 0 additions & 2 deletions web/projects/ui/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import {

import { AppComponent } from './app.component'
import { AppRoutingModule } from './app-routing.module'
import { OSWelcomePageModule } from './modals/os-welcome/os-welcome.module'
import { MarketplaceModule } from './marketplace.module'
import { PreloaderModule } from './app/preloader/preloader.module'
import { FooterModule } from './app/footer/footer.module'
Expand All @@ -47,7 +46,6 @@ import { environment } from '../environments/environment'
PreloaderModule,
FooterModule,
EnterModule,
OSWelcomePageModule,
MarkdownModule,
LoadingModule,
MonacoEditorModule,
Expand Down
5 changes: 4 additions & 1 deletion web/projects/ui/src/app/components/form/control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { inject } from '@angular/core'
import { FormControlComponent } from './form-control/form-control.component'
import { IST } from '@start9labs/start-sdk'

export abstract class Control<Spec extends Exclude<IST.ValueSpec, IST.ValueSpecHidden>, Value> {
export abstract class Control<
Spec extends Exclude<IST.ValueSpec, IST.ValueSpecHidden>,
Value,
> {
private readonly control: FormControlComponent<Spec, Value> =
inject(FormControlComponent)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@
Accept
</button>
</div>
</ng-template>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ export const FORM_CONTROL_PROVIDERS: Provider[] = [
{
provide: TUI_VALIDATION_ERRORS,
deps: [forwardRef(() => FormControlComponent)],
useFactory: (control: FormControlComponent<Exclude<IST.ValueSpec, IST.ValueSpecHidden>, string>) => ({
useFactory: (
control: FormControlComponent<
Exclude<IST.ValueSpec, IST.ValueSpecHidden>,
string
>,
) => ({
required: 'Required',
pattern: ({ requiredPattern }: ValidatorsPatternError) =>
('patterns' in control.spec &&
Expand Down
13 changes: 0 additions & 13 deletions web/projects/ui/src/app/modals/os-welcome/os-welcome.module.ts

This file was deleted.

32 changes: 0 additions & 32 deletions web/projects/ui/src/app/modals/os-welcome/os-welcome.page.html

This file was deleted.

29 changes: 0 additions & 29 deletions web/projects/ui/src/app/modals/os-welcome/os-welcome.page.scss

This file was deleted.

15 changes: 0 additions & 15 deletions web/projects/ui/src/app/modals/os-welcome/os-welcome.page.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ <h2 class="notification-message">{{ truncate(not.message) }}</h2>
>
View Report
</ion-button>
<ion-button
*ngIf="not.code === 2"
slot="end"
fill="clear"
color="dark"
(click)="presentModalMarkdown(not)"
>
View Details
</ion-button>
<ion-button
*ngIf="not.packageId && packageData[not.packageId]"
slot="end"
Expand Down
20 changes: 18 additions & 2 deletions web/projects/ui/src/app/pages/notifications/notifications.page.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { Component } from '@angular/core'
import { ActivatedRoute } from '@angular/router'
import { AlertController, ModalController } from '@ionic/angular'
import { ErrorService, LoadingService } from '@start9labs/shared'
import {
ErrorService,
LoadingService,
MarkdownComponent,
} from '@start9labs/shared'
import { PatchDB } from 'patch-db-client'
import { first } from 'rxjs'
import { BackupReportPage } from 'src/app/modals/backup-report/backup-report.page'
Expand Down Expand Up @@ -115,6 +119,18 @@ export class NotificationsPage {
await modal.present()
}

async presentModalMarkdown(not: ServerNotification<2>) {
const modal = await this.modalCtrl.create({
componentProps: {
title: not.title,
content: not.data,
},
component: MarkdownComponent,
})

await modal.present()
}

async viewFullMessage(header: string, message: string) {
const alert = await this.alertCtrl.create({
header,
Expand All @@ -134,7 +150,7 @@ export class NotificationsPage {
}

truncate(message: string): string {
return message.length <= 240 ? message : '...' + message.substr(-240)
return message.length <= 240 ? message : message.substring(0, 160) + '...'
}

getColor({ level }: ServerNotification<number>): string {
Expand Down
Loading
Loading