Skip to content
This repository has been archived by the owner on Jun 11, 2022. It is now read-only.

Providers in services #9

Open
danyspin97 opened this issue Mar 6, 2020 · 10 comments
Open

Providers in services #9

danyspin97 opened this issue Mar 6, 2020 · 10 comments
Labels
enhancement New feature or request
Milestone

Comments

@danyspin97
Copy link
Owner

Some services need a feature that can be provided by one or more services but they only depend on one (otherwise optional dependencies would have sufficed).

Example

mysql.service

[main]
name = mysql
type = longrun

[run]
build = auto
execute = "mysqld"

mywebapp.system:

[main]
name = mywebapp
type = longrun

[options]
depends#sql = ( mysql postgresql )

When enabling mywebapp, tt will look for both mysql.system and postgresql.system files. In this case the service postgresql cannot be found so mywebapp will depend on mysql service.

Overriding default decision

The default decision can be overriden by creating a file /etc/tt/conf/mywebapp.depends (the exact name/location needs to be finalized) with the following contents:

sql = postgresql

This is also needed when both services are found on the system.

CLI

In addition, the following arguments will be added:

# All providers are set to postgresql (when it is a possible choice)
$ tt enable mywebapp --depends-on postgresql
# depends#sql will use postgresql
$ tt enable mywebapp --depends-on sql#postgresql
# depends#sql in service mywebapp will use postgresql 
$ tt enable mywebapp myotherwebapp --depends-on mywebapp:sql#postgresql

Use cases

  • iptables/nftables
  • udev/mdev[d]
  • Checking if the system is online by depending on one of the manager utilities (connman-is-online, same for NetworkManager and iwd).

Possibilities

Providers chosen for the system in a /etc/tt/depends file and overridden by myservice.depends files.

@Cogitri
Copy link
Collaborator

Cogitri commented Mar 7, 2020

What's the default importance ordering for providers?In depends#sql=( mysql postgresql ) mysql is used if both mysql and pgsql ate available?

@danyspin97
Copy link
Owner Author

If both are provided, the file /etc/tt/conf/mywebapp.depends is needed to choose which one is used. The global system file /etc/tt/depends set defaults without needing a per-service .depends file. For example NetworkManager can be set as network handler and iptables as firewall at a distribution level.

@wozeparrot
Copy link

Will tt throw an error when updating the service database and no option is chosen?

@danyspin97
Copy link
Owner Author

Will tt throw an error when updating the service database and no option is chosen?

Following the above example of mywebapp, it could happen:

  • Only one of mysql and postgresql service is available on the system. The provider is automatically set to the one available and the user is notified about this choice.
  • None of them are available, tt throws an error for a missing dependency.
  • Both are available, tt throws an error because it cannot choose which provider to use.

When, instead of adding a service, the database is updated and a provider has been added to the services, tt still follow the three situations above.

@danyspin97 danyspin97 added the enhancement New feature or request label Nov 6, 2020
@danyspin97 danyspin97 changed the title Providers in services [Proposal] Providers in services Nov 6, 2020
@danyspin97
Copy link
Owner Author

New proposal with virtuals

Another possibility would be to use providers and virtuals together. Example with a user audio setup:

Virtual audio service audio.user:

[main]
name = audio
description = Provides an audio server
type = provider

[options]
providers = [ alsa jack pulseaudio pipewire-pulse ]

Pulseaudio service pulseaudio.user:

[main]
name = pulseaudio
description = Pulseaudio server
type = longrun

[run]
build = path
execute = pulseaudio

Mpd service mpd.user:

[main]
name = mpd
description = MPD server
type = longrun

[run]
build = path
execute = mpd --no-daemon

[options]
dependencies =[ audio ]

This new proposal would require no additional syntax (as oppesed to the initial proposal).

How does it work?

When enabling mpd:

  • if there is no audio provider enabled, tt would throw an error
  • if only one audio provider is enabled, mpd would depends on pulseaudio (most common case)
  • if two or more providers are enabled, a file setting is required

File settings

The file /home/user/.config/tt/virtuals/audio.conf might contain the system setting for that provider:

pulseaudio

The file /home/user/.config/tt/providers/mpd.conf might contain the service setting for any provider:

audio =[ pulseaudio ]
# more providers here

The service setting has priority over the system setting. The latter has priority over automatic choice of providers.

Multiple providers for one virtual

Optionally, multiple providers can be chosen via both system and service setting. For example a web service would require multiple database to work. However, udev and mdev could not work together, so there should be an option allow-multiple-providers (true by default).

@danyspin97 danyspin97 added this to the First release milestone Dec 12, 2020
@Cogitri
Copy link
Collaborator

Cogitri commented Dec 12, 2020

The new proposal sounds better to me since we won't have to declare what services are providers of a certain functionality multiple times (for different services that need that functionality).

@danyspin97
Copy link
Owner Author

The new proposal sounds better to me since we won't have to declare what services are providers of a certain functionality multiple times (for different services that need that functionality).

Yea, that's better. Just modifying a virtual would add a new provider.

One small change over the new proposal is to split dependencies and providers so that it would be simpler to implement (and easier to read too). requires key can be used for providers, for example.

@danyspin97
Copy link
Owner Author

While implementing providers I've found a few things to better define and I'd like to write them down here first:

  • system config (from /etc) shouldn't be read when parsing user services
  • How do providers and virtual interact with instance service (like wireguard@wg0)?
  • allow_multiple_providers is a toggle to every provider in the service and I find it very limited

My idea to fix the third point would be to have differente keys for every require:

  • requires-one: choose one provider only
  • requires-multiple: choose one provider or more (i.e. at least one)
  • requires-optional: optional dependency on single provider for that virtual (I don't think multiple is required here) ((I am not sure this is needed but I leave it for completeness))

Each key corresponds to a different mapping in the config file; a single key/value format will be applied to requires-one and an array format will be applied to requires-multiple.

Regarding the second point, I haven't put much thought in it yet.

@Cogitri
Copy link
Collaborator

Cogitri commented Dec 23, 2020

Not quite sure if I understand the need for requires-one and requires-multiple. At what point would I want to enforce in a service that only one of the providers is up? E.g. if I have a dependency on sql I wouldn't care if postgres and mariadb are both up and I don't really see when you would care.

@danyspin97
Copy link
Owner Author

danyspin97 commented Dec 23, 2020

E.g. if I have a dependency on sql I wouldn't care if postgres and mariadb are both up and I don't really see when you would care.

It would be important for service restarting. If a service has only postgres as sql provider, I don't want to restart it when mariadb goes down.

requires-one and requires-multiple could be used to enforce a service policy. I.e. a service can only depend on one audio provider (requires-one) but a web app could depend on one or more sql databases (requires-multiple).

The user choose his own providers by writing to .config/tt/providers/<service>. A virtual added in requires-multiple would always read this config file as an array, while a virtual added in requires-single would be read a single value there.

By using requires, this file would always be treated as an array, leading to really strange (and mostly wrong) configurations. It would be easier to use tt, but it could not enforce this rule. I think the two configurations are equals in flexibility.

We could also use requires for the time being and add the distinction later, if we think it could be beneficial to services. (After all providers is the main blocker for adding services in tt-services).

EDIT 1:

While writing the implementation, I encountered another issue with requires-single and requires-multiple: they don't work in global settings. This means that the global setting .config/tt/virtual/<virtual_name> can be either:

  • always be treated as an array, and when requires-single is used and multiple providers are found in the global config file, the service config is needed to choose only one (and override global setting)
  • always be treated as a single value, multiple providers only works by adding them in service config file

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants