Skip to content

Installation Instructions

Preparations

Installation

  1. Add limepkg-addon-installer as a dependency to your package.
  2. Create a python module (folder) inside your python package, called installation. The installation module should contain the following:

    • An __init__.py file with a function called get_installation_data. The function should return an InstallationData object. Read more about the InstallationData object here.

      Warning

      The function definition can not be altered!

      from lime_application import LimeApplication
      from limepkg_addon_installer import InstallationData
      
      
      def get_installation_data(
              app: LimeApplication, config: dict) -> InstallationData:
          return InstallationData(...)
      
    • An installer.py file with an Installer class that inherits from BaseInstaller specified in limepkg_addon_installer:

      from limepkg_addon_installer import BaseInstaller
      
      
      class Installer(BaseInstaller):
          def get_module(self) -> str:
              return <path-to-installation-module>
      
          def get_storage_key(self) -> str:
              return <package_name>
      
  3. Extend your get_schema function in your /<package_name>/config/__init__.py file with add-on installer's Setup field:

    from <path-to-installer> import Installer
    
    def get_schema(self):
        installer = Installer(self.application)
        schema = create_schema(self.application)
    
        return installer.inject_installer_field(schema)
    

Installation Data

InstallationData is the object that defines everything that you want to install. Below you can see what is currently supported to install.

  • Database structure - defined by the database_structure key in the InstallationData object. It should be in the same format as LIP's lip.json file.

    {
        "install": {
            "tables": [
                {
                ...
                    "fields": [
                        ...
                    ]
                }
            ]
        }
    }
    
  • Security - defined by the security key in the InstallationData object. It is only possible to install users and groups. The security dict should have the following format:

    {
        "users": [
            # Import UserItem from limepkg_addon_installer
            UserItem(
                # Import LimeUser from lime_authentication.users
                lime_user=LimeUser(...),
    
                # group names (str) this user should be a member of. The group(s)
                # must already exist or be included in the groups section below.
                group_names=[],
    
                # True if the password should be stored or shared with someone.
                # Don't set this if UserType is API as it will be automatically shared!
                display_password=False
            )
        ],
        "groups": [
            # Import GroupItem from limepkg_addon_installer
            GroupItem(
                # Import Group from lime_authentication.users
                lime_group=Group(...)
            )
        ]
    }
    
  • View configuration - defined by the views key in the InstallationData object. The views list should have the following format:

    [ 
        {
            "id": "webclient_views...",
            "version": ...
            "config": {}
        }
    ]
    

    Warning

    It is only possible to install views for new tables, you can not modify existing view configuration!

    Warning

    The view configuration needs to be compatible with the minimum lime-crm of your package, since downgrades are not supported!

  • Settings configs - defined by the settings_configs key in the InstallationData object. These are imported through lime-config-importer. Each item is identified by an id:

    [
        {
            "id": "my_settings_config",    # required, unique config id
            "name": "My settings config",  # optional, shown in the UI
            "version": 1,                  # optional, source version for migration
            "config": {}                   # the config payload to import
        }
    ]
    

    Existing configs are updated; the analysis flags unchanged ones as already up to date.

  • Config-importer configs - defined by the config_importer_configs key in the InstallationData object. This is a list of batches (lists) of config-importer configs. Each config is identified by a key:

    [
        [
            {
                "key": "my_config",     # required, unique key
                "name": "My config",    # optional, shown in the UI
                "config_data": {        # the config-importer ConfigData
                    "key": "my_config",
                    "version": 2,
                    "data": []
                }
            }
        ]
    ]
    
  • Automations - defined by the automations key in the InstallationData object. Each item is an automation in lime-automations DSL format, identified by an id:

    [
        {
            "id": "my_automation",      # required, stable id the installer tracks across installs
            "title": "My automation",
            "trigger": {}
            # ... remaining automation DSL fields
        }
    ]
    

    An automation the installer created before is matched through a stored mapping from its id; otherwise (first install, or automations created by hand) it is matched by title. Matches are updated, new ones are created.

  • Sequences - defined by the sequences key in the InstallationData object. Each item describes a sequence:

    [
        {
            "name": "my_sequence",   # required, unique sequence name
            "title": "My sequence",  # optional, shown in the UI
            "start_value": 1,        # required
            "increment": 1           # required
        }
    ]
    

    Warning

    Sequences are add-only. An existing sequence with the same name is left unchanged, it will never be updated or reset.

  • Manual steps - defined by the manual_steps key in the InstallationData object. A markdown string describing the steps a user has to perform by hand after the automatic installation. It is surfaced in the installation report so the user does not miss it.

    manual_steps = (
        "## After installing\n\n"
        "1. Enter your API key under **Settings -> Integrations**.\n"
        "2. Restart the service.\n"
    )
    

Complete example

A complete installation module for a package called limepkg_acme could look like this. It installs a table, a security group whose name is taken from the installer config, a sequence, and a manual step.

limepkg_acme/installation/__init__.py:

from lime_application import LimeApplication
from lime_authentication.users import Group
from limepkg_addon_installer import GroupItem, InstallationData


def get_installation_data(
        app: LimeApplication, config: dict) -> InstallationData:
    return InstallationData(
        database_structure=_get_database_structure(),
        security=_get_security(config),
        sequences=[
            {
                "name": "acme_order_number",
                "title": "Acme order number",
                "start_value": 1000,
                "increment": 1,
            }
        ],
        manual_steps=(
            "## After installing\n\n"
            "1. Enter your Acme API key under **Settings -> Integrations**.\n"
        ),
    )


def _get_database_structure() -> dict:
    return {
        "install": {
            "tables": [
                {
                    "name": "acme_order",
                    "attributes": {},
                    "localname_singular": {"en": "Order"},
                    "localname_plural": {"en": "Orders"},
                    "fields": [
                        {
                            "table": "acme_order",
                            "name": "reference",
                            "localname": {"en": "Reference"},
                            "attributes": {"fieldtype": "string"},
                        }
                    ],
                }
            ]
        }
    }


def _get_security(config: dict) -> dict:
    group_name = config.get("group_name", "Acme users")
    return {
        "groups": [
            GroupItem(lime_group=Group(name=group_name, description="Acme users"))
        ],
        "users": [],
    }

limepkg_acme/installation/installer.py:

from limepkg_addon_installer import BaseInstaller


class Installer(BaseInstaller):
    def get_module(self) -> str:
        return "limepkg_acme.installation"

    def get_storage_key(self) -> str:
        return "limepkg_acme"

limepkg_acme/config/__init__.py (inject the Setup field into your schema):

from limepkg_acme.installation.installer import Installer


def get_schema(self):
    installer = Installer(self.application)
    schema = create_schema(self.application)

    return installer.inject_installer_field(schema)

Installer Config

To be able to utilize the installer config feature, an installer config schema has to be created. The schema can either be based on your regular Lime Admin config schema or it can be built customly from scratch. The installer config schema is just a standard marshmallow schema.

  • Base installer config on the regular Lime Admin config schema:

    In most cases, the installer config schema should be a subset of your regular Lime Admin config schema. You can therefore explicitly include fields from your Lime Admin config schema to your installer config schema. This way, the amount of duplicated code will be reduced.

    If you want a field from your Lime Admin config schema to be included in your installer config schema, you need to add installer_config=True as an argument to that field.

    field = fields.Str(
        title='foo',
        installer_config=True
    )
    
  • Build custom installer config schema from scratch:

    Building a custom marshmallow schema from scratch gives you more flexibility in terms of what you want to include in your schema.

    Your custom installer config schema can be passed as an argument to the installer's inject_installer_field function in your get_schema function in your /<package_name>/config/__init__.py file.

Checklist

You should have the following at the end of the implementation:

  • installation module inside your python package.
  • installation/__init__.py file with a get_installation_data function that returns an InstallationData object.
  • installation/installer.py file with an implementation of the BaseInstaller interface.
  • Add-on installer's Setup field should be injected in your Lime Admin config schema.
  • If installer config: Installer config schema can be built based on your Lime Admin config schema. A custom installer config schema can also be built from scratch and passed as an argument to the installer's inject_installer_field function.

A screenshot showing the installation folder structure.

Structure of the installation module where database structure is refactored to a separate file.