Add an application

This chapter tells a maintainer how to add an application that operators can deploy from the panel, such as Mastodon, PeerTube or Pixelfed. The maintainer guide tells how to check, deploy and test the change after you add it.

Use Pixelfed as an example: core/components/operator/pixelfed/ has each part that this chapter names. In this chapter, <app> is the name of the new application, in lowercase, for example pixelfed.

What you do not change

The data model makes most of the application from one component. From components.<app>, the code makes these items, and you do not edit them:

  • The operator option applications.<app>, from the module of the component.
  • The form of the panel and the JSON schema of the API, through core/applications-type.nix.
  • The catalog of the API, with the title, description, home page and icon, through core/applications-catalog.nix.
  • The NixOS system nixosConfigurations.operator-<app> and the deploy attributes operator-tf-<app> and operator-tf-incus-<app>, from the node in the roster (see Add the node).
  • The DNS names, from the domain and subdomain options.

The panel and the API have no code for each application. The panel keeps the configuration of a deployment as JSON, thus a new application needs no database migration.

The data model page tells what each field of a component does.

Write the component

  1. If upstream publishes a JSON schema of its configuration, pin it with npins, as pixelfed-config-schema in npins/sources.json. If the nixpkgs package needs a fix, add an overlay in nix/overlays/<app>.nix, and add it to nix/overlays/default.nix.

  2. Make core/components/operator/<app>/default.nix. It sets components.<app>:

    components.<app> = {
      inherit name;
      package = pkgs.<app>;
      artwork = ./artwork.nix;
      optional = true;
      module = import ../../nixosService.nix { ... };
      implementation = cfg: lib.optionalAttrs cfg.enable { ... };
    };
    • description and homepage come from package.meta if you do not set them.

    • artwork is the path of a file in this repository that gives the logo of the application. Use the logo that the upstream project supplies:

      # core/components/operator/<app>/artwork.nix
      { pkgs, ... }:
      {
        icon = "${pkgs.<app>.src}/<path to the logo>.svg";
        # Optional: a variant for dark backgrounds.
        # iconDark = "${pkgs.<app>.src}/<path to the dark logo>.svg";
      }
    • module declares the options that the operator sets. core/components/nixosService.nix makes it from sharedOptions.nix, which gives enable, subdomain and domain, and from the upstream services.<app> options that you name in expose. Name only the options that are the decision of the operator. If an option in expose does not exist, the evaluation fails.

    • implementation changes the settings of the operator into requests for resources. Each attribute is a named group with one request, of a resource in core/resources/:

      Need Request
      Single sign-on "<app>-oidc".oidc
      Email "<app>-smtp".smtp
      Cache "<app>-cache".redis
      Database "<app>-db".postgresql
      Object storage and a backup "<app>-bucket".garage, with the helpers of core/components/operator/app-resources.nix
      TLS certificate "tls".ssl.domains = [ cfg.domain ];
      Open ports "web".firewall.publicTCPPorts = [ 80 443 ];
      Workload identity "spiffe".spiffe.enable = true;
      Generated secrets "vars-backend".generateFiles.instances.<app>-app
      The other NixOS settings "<name>".nixos-module.module

      A request can have a nixos-configuration function. It gets the result of the resource, for example the OIDC client secret, and sets the NixOS options of the application from it. The hosting resources page lists the options of each request.

  3. Add ./<app> to the imports of core/components/operator/default.nix.

Add the node

Each application runs on its own node. Add the node to the roster in core/setups/groups/operator.nix, in machines.published:

{
  pixelfed = 54;
  peertube = 55;
  mastodon = 56;
  <app> = 57;
}

The name of the node must be the name of the component. The number gives the documentation addresses 192.0.2.<n> and 2001:db8::<n>, which a deploy replaces. Use a number that no other node uses.

If you do not add the node, the application is in the form, but a deploy does not deploy it, and no check fails.

Then add the application at this location:

Audit the options

core/components/operator/operator-facing-options.csv has one row for each setting of each application. Each row tells if the setting is for the operator or for Fediversity. Add a row for each services.<app> option, and for each key of the upstream configuration. A row can use a trailing * for a group of keys. Use this audit to select the options in expose, and the settings that the form shows.

Then add the version that you audited to the list in the operator configuration page.

The build does not read the file, thus no check finds a missing row.

Add the checks

  1. Make core/components/operator/<app>/test.nix. It calls mkAppTest from core/components/operator/testing/lib.nix, which deploys the application on one node, with an SSO provider, a mail relay, a directory and object storage beside it. Add a test script that logs in and uses the application.

  2. In core/checks/default.nix, add the test as a check, and give it a description:

    test-<app>-service = runNixOSTest {
      imports = [ ../components/operator/<app>/test.nix ];
      _module.args.sources = sources;
    };

    The description becomes the meta.description of the check, which the flake attributes page shows. No check finds a missing description.

  3. In core/checks/ci.nix, tell CI where to run the check, and on which changes. Copy the entry of test-pixelfed-service. If a check has no entry, the evaluation fails.

  4. In .forgejo/workflows/nix-flake-check.sh, add a case for operator-<app> beside operator-pixelfed. Without it, CI builds the node on each change of the repository.

  5. Make the CI workflows again:

    bash .forgejo/workflows/nix-flake-check.sh

    This adds checks-test-<app>-service.yaml, and a job for the node in nixosConfigurations-operator.yaml. CI fails if the workflows are not up to date.

The apps-tf, apps-tf-incus and apps-api tests deploy only Pixelfed, as a sample of all applications. You do not change them.

Update the specifications and the documentation

No check finds these, thus look at each one:

Check the result

Do the steps of Check a change without a deploy in the maintainer guide:

nix build ./core#nixosConfigurations.operator-<app>.config.system.build.toplevel
nix build ./core#checks.x86_64-linux.test-<app>-service

Then test the operator branch from the panel: the form shows the new application from the schema of your branch.