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

Per-environment configuration #210

Open
bajtos opened this issue May 11, 2023 · 8 comments
Open

Per-environment configuration #210

bajtos opened this issue May 11, 2023 · 8 comments
Assignees
Labels
feature New feature or request

Comments

@bajtos
Copy link
Member

bajtos commented May 11, 2023

A typical Zinnia module needs to support at least three different environments:

  • Local development
  • Integration/end-to-end tests
  • Production (deployed to Filecoin Station instances)

Each environment usually requires a different configuration.

For example, a module interacting with FVM smart contracts can use one of the testnets for local development, a special-purpose net when running the tests on CI, and the mainnet when deployed to Stations.

Zinnia should provide means for module authors to change this configuration.

@juliangruber
Copy link
Member

Is this the job of Zinnia? Node.js is fine without providing environments, since they can be implemented in user land. Solutions use config files and env vars. Do you think Zinnia could provide guidance rather than a solution here?

@juliangruber
Copy link
Member

Do Deno and Go provide environments? I think if we stand on the shoulders of giants we'll be safer off for now

@bajtos
Copy link
Member Author

bajtos commented May 15, 2023

Sure, providing guidance is enough as long as we have the lower-level building blocks in place.

Solutions use config files and env vars.

Here is the catch: Zinnia modules cannot read environment variables and don't have access to the filesystem except by importing JavaScript source code files from the module's codebase.

I am thinking about the following solution:

  1. Environment-specific configuration is stored in a JS file, e.g. config.js.
  2. This file IS NOT versioned in git. Instead, there is config.template.js describing configuration options.
  3. Developers create their own config.js in the local clone/checkout of the git repository, using config.template.js as a starter kit or obtaining a working dev config from another developer.
  4. CI/CD pipeline creates config.js as part of the env setup.
  5. In the Filecoin Station, each Zinnia module will be accompanied by a config file.

WDYT about such solution, @juliangruber? Does it feel ergonomic and easy to use?

@juliangruber
Copy link
Member

juliangruber commented May 15, 2023

I think that will work! I had thought you wanted to support ZINNIA_ENV=(dev|test|production), but if it's just a file with config and Zinnia is not opinionated about certain environments then +1 from me

In the Filecoin Station, each Zinnia module will be accompanied by a config file.

How do you envision this works? The module author needs some way to tell Zinnia which config to provide inside Station, right? Would repos have config.template.js and config.station.js?

Could we rather expose something like Zinnia.inStation, and then the module code can decide whether to read from config.js or config.station.js, or something else completely? I think CI also doesn't really need to write a config file: If you module's lib lets you pass in all config as arguments, then it doesn't need to read config from disk.

So my proposal would be to expose Zinnia.inStation and let the module author handle configuration any way they want. They can have a config object in their single file, they can have a config file, multiple config files, etc.

FYI, I personally dislike config templates for projects because they raise the barrier to entry. For security critical projects it's better to get a config from a coworker and be aware of everything that's configured, but for open source modules I don't think that's required. Therefore I'd suggest that if we go with the config.js convention, to just have config.js committed to git.

@bajtos
Copy link
Member Author

bajtos commented May 16, 2023

In the Filecoin Station, each Zinnia module will be accompanied by a config file.

How do you envision this works? The module author needs some way to tell Zinnia which config to provide inside Station, right? Would repos have config.template.js and config.station.js?

In my vision, there will be no config.station.js. Station-specific configuration will live inside Station Core repository, together with other module-specific configuration like which version (git tag) to download and the GitHub repository name where to download from.

In an ideal world, when the module author wants to deploy a new module version to Stations, they will provide both source code and configuration options to us.

Could we rather expose something like Zinnia.inStation, and then the module code can decide whether to read from config.js or config.station.js, or something else completely? I think CI also doesn't really need to write a config file: If you module's lib lets you pass in all config as arguments, then it doesn't need to read config from disk.

So my proposal would be to expose Zinnia.inStation and let the module author handle configuration any way they want. They can have a config object in their single file, they can have a config file, multiple config files, etc.

I am not a fan of using environment name or type to decide which config values to use. Quoting from https://12factor.net/config:

Another aspect of config management is grouping. Sometimes apps batch config into named groups (often called “environments”) named after specific deploys, such as the development, test, and production environments in Rails. This method does not scale cleanly: as more deploys of the app are created, new environment names are necessary, such as staging or qa. As the project grows further, developers may add their own special environments like joes-staging, resulting in a combinatorial explosion of config which makes managing deploys of the app very brittle.

In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime.

12factor recommends using environment variables. We don't have that in Zinnia and Station, and I think such a feature does not belong to our platform. Even if we supported environment variables, we would need to set env vars on a per-module basis inside Station, which would get us back to the config file approach (at least in spirit).

FYI, I personally dislike config templates for projects because they raise the barrier to entry. For security critical projects it's better to get a config from a coworker and be aware of everything that's configured, but for open source modules I don't think that's required. Therefore I'd suggest that if we go with the config.js convention, to just have config.js committed to git.

I see your point and I agree with you that config templates are a bit of a pain.

I am fine to commit config.js to git.

Even when the file is in git, we can still replace it with a different config e.g. when running inside the Station.

@juliangruber
Copy link
Member

In my vision, there will be no config.station.js. Station-specific configuration will live inside Station Core repository, together with other module-specific configuration like which version (git tag) to download and the GitHub repository name where to download from.

How would Station Core pass the config? I assume like this:

  1. Station downloads & unpacks module archive into modules/$name
  2. Station overwrites modules/${name}/config.js from modules/configs/${name}.js

I am not a fan of using environment name or type to decide which config values to use

If there is no "station environment", then Station will need to know about all of the configuration for a module. To me Station shouldn't need to know about that, because that's only the module's business. Station can tell a module how much disk space to use, but not which influx endpoint to connect to.

As a module author I wouldn't want to give Station control over all settings, some I should own. And for these, it's useful to know whether I'm running inside Station. Playing devil's advocate, I as a module author could just say: "I accept one option in config.json, which is called "inStation": Boolean.

@bajtos
Copy link
Member Author

bajtos commented May 16, 2023

In my vision, there will be no config.station.js. Station-specific configuration will live inside Station Core repository, together with other module-specific configuration like which version (git tag) to download and the GitHub repository name where to download from.

How would Station Core pass the config? I assume like this:

  1. Station downloads & unpacks module archive into modules/$name
  2. Station overwrites modules/${name}/config.js from modules/configs/${name}.js

Yes, that's what I had in my mind. We may end up choosing a different location for modules/config/${name}.js, but that's an implementation detail.

Ideally, I would like the per-module config.js file to live next to the file where we define other module properties like name, GitHub repository, git tag (version), etc.

See https://github.com/filecoin-station/core/blob/b4d1767a9644994b21d24bac759e96c90535d0a8/lib/zinnia.js#L10-L16

const ZINNIA_MODULES = [
  {
    module: 'peer-checker',
    repo: 'filecoin-station/mod-peer-checker',
    distTag: 'v1.0.0'
  }
]

I am not a fan of using environment name or type to decide which config values to use

If there is no "station environment", then Station will need to know about all of the configuration for a module. To me Station shouldn't need to know about that, because that's only the module's business. Station can tell a module how much disk space to use, but not which influx endpoint to connect to.

As a module author I wouldn't want to give Station control over all settings, some I should own. And for these, it's useful to know whether I'm running inside Station. Playing devil's advocate, I as a module author could just say: "I accept one option in config.json, which is called "inStation": Boolean.

I think see your point.

In my mind, the module author is already giving Station full control over everything, both the code and settings. They have to trust us that the code that ends up bundled into Station Core is exactly what they wanted.

As a Station maintainer, I don't want to understand details of module configuration. I want the module maintainer to give me both the source code and the configuration values. I think we agree on that.

Our opinion seems to differ on the practical implementation of how the module author is going to give use the source code and the configuration, especially whether they are the same thing or two different things.

I'd like to make it easier for module authors to keep the configuration (mostly) independent from their source code. Since we don't have env variables, a single config file replacing environment variables seems like a good solution to me.

Sure, they can say I accept one option in config.json, which is called "inStation": Boolean and I am totally fine with that. In the same way as with 12factor, where an app can say I accept one environment variable called NODE_ENV which should be set to production.

At the same time, I think such an approach is not ideal, and we should make it easier for module authors to do better. Hence my proposal from config.js.

Maybe config.json would be a more appropriate replacement for environment variables. Then we could put the configuration literally into the ZINNIA_MODULES definition.

I was not sure if it was possible to import JSON files in Deno/Zinnia. Since we verified that together today, changing my proposal to use config.json instead of config.js is an option if you find it better that way.

Again, I don't want us to deal with details of module configuration, but I want a way for module authors to give us configuration to be used when their module is deployed to Stations.

@juliangruber
Copy link
Member

As a Station maintainer, I don't want to understand details of module configuration. I want the module maintainer to give me both the source code and the configuration values. I think we agree on that.

After having integrated Bacalhau, I had wished that the Bacalhau team maintained the config. I needed to get our config reviewed by them, and when there is a change I need to ask them how to properly update the flags. So my experience is the opposite of what you want, but it's also only one example so who knows.

If we add config.json, I think we can solve even more with it: Just yesterday we discussed having a config file that marks the module root directory. What if we now introduce module.json, which will have the module config and is used to denote the entry point?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
Status: 🗃 backlog
Development

No branches or pull requests

2 participants