diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3ac5556c..7b1b54b9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -99,6 +99,7 @@ jobs: mv mkosi.output/incus-ceph.raw upload/ mv mkosi.output/incus-linstor.raw upload/ mv mkosi.output/migration-manager.raw upload/ + mv mkosi.output/openfga.raw upload/ mv mkosi.output/operations-center.raw upload/ mv mkosi.output/IncusOS_${{ github.ref_name }}.raw upload/IncusOS_${{ github.ref_name }}.img diff --git a/.gitignore b/.gitignore index 5c04f773..eabb6941 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ certs/ mkosi.images/base/mkosi.extra/boot/EFI/ mkosi.images/base/mkosi.extra/usr/local/bin/ mkosi.images/migration-manager/mkosi.extra/ +mkosi.images/openfga/mkosi.extra/ mkosi.images/operations-center/mkosi.extra/ app-build/ diff --git a/Makefile b/Makefile index 84e2a557..406a4745 100644 --- a/Makefile +++ b/Makefile @@ -167,6 +167,7 @@ test-applications: incus file push mkosi.output/incus-ceph.raw test-incus-os/root/updates/ incus file push mkosi.output/incus-linstor.raw test-incus-os/root/updates/ incus file push mkosi.output/migration-manager.raw test-incus-os/root/updates/ + incus file push mkosi.output/openfga.raw test-incus-os/root/updates/ incus file push mkosi.output/operations-center.raw test-incus-os/root/updates/ incus exec test-incus-os -- curl --unix-socket /run/incus-os/unix.socket http://localhost/1.0/system/update/:check -X POST @@ -184,6 +185,7 @@ test-update: incus file push mkosi.output/incus-ceph.raw test-incus-os/root/updates/ incus file push mkosi.output/incus-linstor.raw test-incus-os/root/updates/ incus file push mkosi.output/migration-manager.raw test-incus-os/root/updates/ + incus file push mkosi.output/openfga.raw test-incus-os/root/updates/ incus file push mkosi.output/operations-center.raw test-incus-os/root/updates/ incus exec test-incus-os -- curl --unix-socket /run/incus-os/unix.socket http://localhost/1.0/system/update/:check -X POST diff --git a/app-build/applications.json b/app-build/applications.json index 1bc2fe84..acf3aa90 100644 --- a/app-build/applications.json +++ b/app-build/applications.json @@ -85,6 +85,24 @@ "usr/share/migration-manager/" ] }, + "openfga": { + "version": "1.11.1", + "repo": "https://github.com/openfga/openfga.git", + "build_targets": [ + [ + "./cmd/openfga" + ] + ], + "install_targets": [ + [ + "openfga", + "usr/local/bin/" + ] + ], + "clean_targets": [ + "usr/local/bin/openfga" + ] + }, "opentofu": { "version": "1.10.7", "repo": "https://github.com/opentofu/opentofu.git", @@ -274,4 +292,4 @@ "usr/share/terraform/plugins/registry.opentofu.org/hashicorp/time/" ] } -} \ No newline at end of file +} diff --git a/app-build/build-applications.py b/app-build/build-applications.py index 9a8dc23b..887de758 100755 --- a/app-build/build-applications.py +++ b/app-build/build-applications.py @@ -21,6 +21,7 @@ images = [ ["base", ["incus-osd", "kpx", "tailscale"]], ["migration-manager", ["migration-manager"]], + ["openfga", ["openfga"]], ["operations-center", [ "opentofu", "operations-center", diff --git a/incus-osd/api/images/update_file_component.go b/incus-osd/api/images/update_file_component.go index d40c0b77..7cc602f9 100644 --- a/incus-osd/api/images/update_file_component.go +++ b/incus-osd/api/images/update_file_component.go @@ -16,12 +16,15 @@ const ( // UpdateFileComponentIncusLinstor represents a Linstor application update for Incus. UpdateFileComponentIncusLinstor UpdateFileComponent = "incus-linstor" - // UpdateFileComponentOperationsCenter represents an Operations Center application update. - UpdateFileComponentOperationsCenter UpdateFileComponent = "operations-center" - // UpdateFileComponentMigrationManager represents a Migration Manager application update. UpdateFileComponentMigrationManager UpdateFileComponent = "migration-manager" + // UpdateFileComponentOpenFGA represents an OpenFGA application update. + UpdateFileComponentOpenFGA UpdateFileComponent = "openfga" + + // UpdateFileComponentOperationsCenter represents an Operations Center application update. + UpdateFileComponentOperationsCenter UpdateFileComponent = "operations-center" + // UpdateFileComponentDebug represents a debug application update. UpdateFileComponentDebug UpdateFileComponent = "debug" ) @@ -33,6 +36,7 @@ var UpdateFileComponents = map[UpdateFileComponent]struct{}{ UpdateFileComponentIncusCeph: {}, UpdateFileComponentIncusLinstor: {}, UpdateFileComponentMigrationManager: {}, + UpdateFileComponentOpenFGA: {}, UpdateFileComponentOperationsCenter: {}, UpdateFileComponentDebug: {}, } diff --git a/incus-osd/cmd/image-publisher/main_sync.go b/incus-osd/cmd/image-publisher/main_sync.go index c72bcb02..7d2bf615 100644 --- a/incus-osd/cmd/image-publisher/main_sync.go +++ b/incus-osd/cmd/image-publisher/main_sync.go @@ -284,12 +284,15 @@ func (*cmdSync) downloadImage(ctx context.Context, archName string, releaseURL * case assetName == "incus-linstor.raw.gz": assetComponent = apiupdate.UpdateFileComponentIncusLinstor assetType = apiupdate.UpdateFileTypeApplication - case assetName == "operations-center.raw.gz": - assetComponent = apiupdate.UpdateFileComponentOperationsCenter - assetType = apiupdate.UpdateFileTypeApplication case assetName == "migration-manager.raw.gz": assetComponent = apiupdate.UpdateFileComponentMigrationManager assetType = apiupdate.UpdateFileTypeApplication + case assetName == "openfga.raw.gz": + assetComponent = apiupdate.UpdateFileComponentOpenFGA + assetType = apiupdate.UpdateFileTypeApplication + case assetName == "operations-center.raw.gz": + assetComponent = apiupdate.UpdateFileComponentOperationsCenter + assetType = apiupdate.UpdateFileTypeApplication case strings.HasSuffix(assetName, ".efi.gz"): assetComponent = apiupdate.UpdateFileComponentOS assetType = apiupdate.UpdateFileTypeUpdateEFI @@ -317,6 +320,9 @@ func (*cmdSync) downloadImage(ctx context.Context, archName string, releaseURL * case strings.HasSuffix(assetName, "migration-manager.manifest.json.gz"): assetComponent = apiupdate.UpdateFileComponentMigrationManager assetType = apiupdate.UpdateFileTypeImageManifest + case strings.HasSuffix(assetName, "openfga.manifest.json.gz"): + assetComponent = apiupdate.UpdateFileComponentOpenFGA + assetType = apiupdate.UpdateFileTypeImageManifest case strings.HasSuffix(assetName, "operations-center.manifest.json.gz"): assetComponent = apiupdate.UpdateFileComponentOperationsCenter assetType = apiupdate.UpdateFileTypeImageManifest diff --git a/incus-osd/internal/applications/app_openfga.go b/incus-osd/internal/applications/app_openfga.go new file mode 100644 index 00000000..6771f5c7 --- /dev/null +++ b/incus-osd/internal/applications/app_openfga.go @@ -0,0 +1,93 @@ +package applications + +import ( + "context" + "crypto/tls" + "errors" + "io" + + "github.com/lxc/incus-os/incus-osd/internal/systemd" +) + +type openfga struct { + common +} + +// Start starts the systemd unit. +func (*openfga) Start(ctx context.Context, _ string) error { + // Start the unit. + return systemd.EnableUnit(ctx, true, "openfga.service") +} + +// Stop stops the systemd unit. +func (*openfga) Stop(ctx context.Context, _ string) error { + // Stop the unit. + return systemd.StopUnit(ctx, "openfga.service") +} + +// Restart restarts the main systemd unit. +func (*openfga) Restart(ctx context.Context, _ string) error { + return systemd.RestartUnit(ctx, "openfga.service") +} + +// Update triggers restart after an application update. +func (*openfga) Update(ctx context.Context, _ string) error { + // Reload the systemd daemon to pickup any service definition changes. + err := systemd.ReloadDaemon(ctx) + if err != nil { + return err + } + + // Restart the unit. + return systemd.RestartUnit(ctx, "openfga.service") +} + +// Initialize runs first time initialization. +func (*openfga) Initialize(_ context.Context) error { + return nil +} + +// IsRunning reports if the application is currently running. +func (*openfga) IsRunning(ctx context.Context) bool { + return systemd.IsActive(ctx, "openfga.service") +} + +// GetCertificate returns the keypair for the server certificate. +func (*openfga) GetCertificate() (*tls.Certificate, error) { + return nil, errors.New("not supported") +} + +// GetDependencies returns a list of other applications this application depends on. +func (*openfga) GetDependencies() []string { + return nil +} + +// AddTrustedCertificate adds a new trusted certificate to the application. +func (*openfga) AddTrustedCertificate(_ context.Context, _ string, _ string) error { + return errors.New("not supported") +} + +// IsPrimary reports if the application is a primary application. +func (*openfga) IsPrimary() bool { + return false +} + +// FactoryReset performs a full factory reset of the application. +func (*openfga) FactoryReset(_ context.Context) error { + return errors.New("not supported") +} + +// WipeLocalData removes local data created by the application. +func (*openfga) WipeLocalData() error { + return errors.New("not supported") +} + +// GetBackup returns a tar archive backup of the application's configuration and/or state. +func (*openfga) GetBackup(_ io.Writer, _ bool) error { + return errors.New("not supported") +} + +// RestoreBackup restores a tar archive backup of the application's configuration and/or state. +func (*openfga) RestoreBackup(_ context.Context, _ io.Reader) error { + return errors.New("not supported") +} diff --git a/incus-osd/internal/applications/load.go b/incus-osd/internal/applications/load.go index 001beb48..f374013c 100644 --- a/incus-osd/internal/applications/load.go +++ b/incus-osd/internal/applications/load.go @@ -25,6 +25,8 @@ func Load(_ context.Context, s *state.State, name string) (Application, error) { app = &incusLinstor{common: common{state: s}} case "migration-manager": app = &migrationManager{common: common{state: s}} + case "openfga": + app = &openfga{common: common{state: s}} case "operations-center": app = &operationsCenter{common: common{state: s}} default: diff --git a/mkosi.images/openfga/mkosi.conf b/mkosi.images/openfga/mkosi.conf new file mode 100644 index 00000000..e44d0374 --- /dev/null +++ b/mkosi.images/openfga/mkosi.conf @@ -0,0 +1,13 @@ +[Config] +Dependencies=base + +[Output] +Format=sysext +Overlay=yes +ManifestFormat=json +ImageVersion= + +[Content] +BaseTrees=%O/base +Packages= + postgresql diff --git a/mkosi.images/openfga/mkosi.extra/usr/lib/systemd/system/openfga.service b/mkosi.images/openfga/mkosi.extra/usr/lib/systemd/system/openfga.service new file mode 100644 index 00000000..270350a1 --- /dev/null +++ b/mkosi.images/openfga/mkosi.extra/usr/lib/systemd/system/openfga.service @@ -0,0 +1,10 @@ +[Unit] +Description=OpenFGA +Documentation=https://github.com/openfga/openfga + +[Service] +ExecStartPre=mkdir -p /var/lib/openfga/ +ExecStartPre=/usr/local/bin/openfga migrate --datastore-engine=sqlite --datastore-uri=file:///var/lib/openfga/openfga.sqlite +ExecStart=/usr/local/bin/openfga run --playground-enabled=false --datastore-engine=sqlite --datastore-uri=file:///var/lib/openfga/openfga.sqlite +KillMode=process +Restart=on-failure