# Design: Profiles **Author**: @aat <!-- Status of the document - draft, in-review, etc. - is conveyed via HackMD labels --> ## Description (what) Introduce the concept of profiles to replace `ftl-project.toml`, similar to how profiles work in a number of other similar systems such as [kubectl](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/) contexts. FTL profiles will differ in some ways though, as they will be designed to be checked into a repository. ## Motivation (why) - The current mechanism for switching between contexts is via `--config`, which is both tedious and easy to forget to use. - Because the FTL tooling is only aware of a single configuration file at once, there's no way to build tooling for working across multiple profiles, such as eg. copying secrets/config between profiles, etc. - Supporting multiple config/secret providers per config is confusing. ## Goals - Make it easier to reason about managing multiple clusters. - Simplify using different combinations of features/configuration: - Local vs. remote cluster. - Local vs. remote secrets/config. - Locally, support offline management of secrets/config. - Simplify managing secrets/config: - Remove the ability to mix/match secrets/config providers within a single cluster. Each cluster, whether local or remote, has a single provider for each type. ## Non-goals - It's unclear whether we should have a first class concept of "test" or "integration-test" profiles, but we'll see how that falls out. ## Design (how) Profiles will specify the cluster endpoint, whether it is ephemeral (`ftl dev`) or persistent, and for ephemeral clusters the profile will also specify the secret+config providers to support "offline" management. There will always be a "default" profile which will be used if no other profile is specified. The default profile can be overridden locally (not persisted to git) by issuing a command. Tests will always use the "default" profile unless otherwise specified. ### Code Management of `.ftl-project` will be isolated to an internal package. The public API wrapping this will return a `Profile`, probably an interface with local+remote implementations. For local clusters, the `Profile` will either update secrets/config through the cluster itself if available, or directly if the cluster is not live. The `Profile` interface will look something like this: ```go type Profile interface { // ProjectConfig is static project-wide configuration shared by all profiles, such as realm, module roots, etc.. ProjectConfig() ProjectConfig // ProfileConfig is the static configuration for a Profile. // // This includes the name, endpoint, etc. ProfileConfig() ProfileConfig SecretsManager() *manager.Manager[configuration.Secrets] ConfigurationManager() *manager.Manager[configuration.Configuration] } ``` ### Filesystem layout Currently for local development, secrets+config are tightly coupled with the `ftl-project.toml` file. The new design will separate these into distinct files. To support this we'll introduce a directory hierarchy somewhat like this: ``` .ftl-project/ project.json profiles/ <profile>/ profile.json [ secre] [config.json] ``` `profiles.json` will contain all profile definitions. ### CLI #### Set project-wide configuration ``` $ ftl init --no-git --realm="NAME" --module-roots="DIR,..." ``` #### List profiles List available profiles, whether they're default, local or remote, what secrets+config providers they use, etc. ``` $ ftl profile list ``` #### Set the default profile This will change the _persisted_ default profile: ``` $ ftl profile default <profile> ``` #### Switch profiles Switch the currently active profile on your machine: ``` $ ftl profile switch <profile> ``` This command will write the profile name to `$CACHEDIR/ftl/<project-path-hash>/default-profile`, eg. for a project in `/Users/alec/dev/project` this would end up in `~/Library/Caches/ftl/c0f1410a1a21a4cd452b6097e663057ee6622d88/default-profile`. #### Create a new remote cluster profile ``` $ ftl profile new <name> --remote=<endpoint> ``` #### Create a new local cluster profile ``` $ ftl profile new <name> \ --local \ --secrets=<secret-provider> \ --configuration=<config-provider> ``` Local profiles will default to inline secrets and configuration providers. eg. Create a new local "devel" profile with inline secrets+config: ``` $ ftl profile new devel --local ``` Create a new local "smoketest" profile with secrets stored in 1Password: ``` $ ftl profile new smoketest --local --secrets=1password ``` #### Cloning a profile ``` $ ftl profile clone <from> <to> ``` #### Diffing two profiles ``` $ ftl profile diff <a> <b> ``` #### Dump the state of a profile ``` $ ftl profile dump <profile> ``` ### Required changes (how) - Create a `configuration.FileResolver` which stores secrets/config in `.ftl-project/<role>/<profile>.json` - Add package to manage profiles. - Remove `configuration.ProjectConfigResolver`. - Update go-runtime to support profiles. - Replace `--config` flag with `--profile` for overriding the profile per-command. - Add `ftl profile` commands (see above). - Add `RemoteRouter` + `RemoteProvider` that use gRPC to a cluster. - Refactor `AdminService` so there is no ability to select a provider. - Finally, refactor `Manager` so it only supports a single provider. ## Rejected Alternatives (optional) <!-- Other ideas that were considered but rejected, including reasoning. -->