# Prospero documentation

## 1. Overview

Prospero is a tool designed to install and manage updates of Wildfly servers.

The tool supports:

- Provisioning Wildfly servers

- Updating Wildfly servers

- Reverting updates to Wildfly servers

- Tracking updates history

- Management of update sources

Prospero includes a CLI client and a programmatic API.

Releases of the command line tool will be available at https://github.com/wildfly-extras/prospero/releases/.

To use the tool, download and unzip the release zip, then add the bin directory to your system path. Use `prospero.sh` or `prospero.bat` to launch the tool.

## 2. Concepts

The Wildfly servers are assembled from a large number of dependencies from various projects. If any of those components is changed, in the traditional update process, the server has to be rebuilt with updated components and distributed as a new version.

Prospero aims to simplify this process by allowing users to apply updated components to already provisioned servers.

To achieve that, Prospero utilizes two projects - Galleon and Wildfly Channels.

### 2.1. Feature Packs

Galleon is a provisioning tool used to assemble Wildfly distributions. In order for a piece of software to be provisioned by Galleon it needs to be packaged as a feature-pack.

Feature packs are ZIP archives usually available in Maven repositories. They contain information about installed software’s filesystem content, configuration and additional tasks needed to assemble and configure it.

In case of Wildfly server, the feature pack also contains a list of Maven coordinates for all the components included in the server distribution. During provisioning, those coordinates are used to download the components and place them in resulting server.

For more information on Galleon and the Feature Packs see the Galleon documentation

### 2.2. Channels

Wildfly Channels are a way to provide a curated list of compatible, up-to-date components. A channel consists of a YAML definition file and one or more underlying Maven repositories.

There are two types of Wildfly Channels supported by Prospero - open channels and manifest channels. Open channels allow access to the latest artifacts in the underlying repository, while manifest channels define a list of allowed list of components.

For more information on Wildfly Channels see the spec documentation.

#### 2.2.1. Manifest channels

One way to specify channel content is by using manifests. Manifests are YAML file listing streams available in the channel. For example a part of wildfly-27.0.0 manifest looks like:

    schemaVersion: "1.0.0"
    name: Manifest for WildFly 27
    description: |-
      This manifest provides updates for WildFly 27 Feature Pack.
    streams:
      - groupId: "org.wildfly"
        artifactId: "wildfly-galleon-pack"
        version: "27.0.0.Final"

      - groupId: "org.wildfly"
        artifactId: "wildfly-ee-galleon-pack"
        version: "27.0.0.Final"

      - groupId: "org.wildfly.core"
        artifactId: "wildfly-core-galleon-pack"
        version: "19.0.0.Beta13"

      - groupId: "org.wildfly.core"
        artifactId: "wildfly-version"
        version: "19.0.0.Final"

      - groupId: "org.wildfly.security"
        artifactId: "wildfly-elytron-jaspi"
        version: "1.20.2.Final"

The channel using this manifest would be defined as:

    schemaVersion: "2.0.0"
    name: Channel for WildFly 27
    manifest:
      maven:
        groupId: org.wildfly.channels
        artifactId: wildfly-27.0
    repositories:
      - id: central
        url: https://repo1.maven.org/maven2/

When resolving artifacts using such channel, the versions of artifacts will be dictated by the manifest, even if newer version is available in the channel repositories.

Note | The manifest can be distributed as either a static file (referenced in a channel by a URL), or as an artifact in a Maven repository.

#### 2.2.2. Open channels

Alternatively the channel can be defined to use the latest versions of artifacts available in its repositories.

    schemaVersion: "2.0.0"
    name: Channel for WildFly 27
    resolve-if-no-stream: latest
    repositories:
      - id: central
        url: https://repo1.maven.org/maven2/

## 3. General provisioning process

### 3.1. Installation process

Prospero delegates provisioning server to Galleon. When Galleon attempts to resolve components needed by the server, instead of using versions provided by the feature packs, Prospero intercepts that request and uses Wildfly Channels to find the correct version of the component and resolve it from the channels repositories.

Every time a server is provisioned, it will receive the latest available components.

### 3.2. Update process

When new versions of components are made available, Prospero can apply those to existing servers. In order to find updates following steps are executed:

1. Download the latest version of channel manifests from Maven repositories

2. Compare component versions in the server to the latest available versions in channels.

If updates are available, they will be applied to the server in a following process:

1. Provision a new, updated server in a temporary directory.

2. Compare the changes between the new and old server.

3. Apply changes in the new server to the base server.

#### 3.2.1. Resolving update conflicts

Generally user modified files in the server will never be changed during the update.

Sometimes server files might be modified both in the base server and in an incoming update. An example of this might be a configuration file changed by the user to support their setup and changed in the update to modify a default configuration value.

In such case, the user changes are persisted and not modified. The new, updated file configuration is created next to the old file with a `.glnew` suffix, and the user is notified that there was a conflict. The user can resolve the conflict manually after the update.

The exception to this rule are files considered to be `system paths`. They should not be modified by the user and will always be kept in sync with the changes provided by the updates. Any user changes will be replaced during the update and stored with a `.glold` suffix. An example of such files is a content of `modules/system` folder.

User modified | Update modified | System path | Resolution
Y | N | n/a | Original file is used.
N | Y | n/a | Updated version is used. Original file is discarded
Y | Y | Y | Updated version is used. Original file is persisted with `.glold` suffix
Y | Y | N | Original file is used. Updated version is persisted with `.glnew` suffix

#### 3.2.2. Update operation limitations

During "apply changes" phase of updates, any processes using server’s resources need to be stopped to avoid resource locking issues. The user should manually shut down the server before performing update.

To reduce server downtime, the update operation can be performed in two steps - `prepare` and `apply`. In the first step, a candidate update server is provisioned in a new directory. The second step, compares the changes between the candidate and the base server and applies them to the base server.

If the update is split into separate steps, the `prepare` step can be performed while the server is running. See Working with update candidates for details.

#### 3.2.3. Update backup

The only time changes to the server are applied is during the `apply` phase of the update. To avoid leaving the server in a corrupted state, before any changes are written out, the current state of the server is preserved in an `<SERVER_ROOT>/.update.old` folder.

Should an error occur during the operation, Prospero will attempt to restore the state from the backup. If that is not possible, or the update process was either canceled or crashed, the backup folder will be preserved and manual restore can be performed.

## 4. Prospero server metadata

In order for Prospero to be able to update a server, the server installation has to contain some additional metadata files. Those files contain information about server’s current state and the subscribed channels. The metadata is generated when the server is installed and can be modified using Prospero commands.

The metadata is split between `<SERVER_HOME>/.galleon` and `<SERVER_HOME>/.installation` folders.

File | Description
`<SERVER_HOME>/.installation/installer-channels.yaml` | List of channels the server is subscribed to receive updates from
`<SERVER_HOME>/.installation/manifest.yaml` | Record of current versions of components installed in the server
`<SERVER_HOME>/.installation/manifest_version.yaml` | Record of channel manifests used to provision current server.
`<SERVER_HOME>/.galleon/provisioning.xml` `<SERVER_HOME>/.galleon/provisioned.xml` | Gallon files recording provisioned feature-packs and their customizations.

### 4.1. Prospero update history

The files in the `.installation/` and `.galleon/` folders should only be modified via the prospero tool, not manually. All metadata changes performed by prospero tool are internally versioned and can be later reviewed or rolled back by using the `prospero history` and `prospero revert` commands.

## 5. Usage

### 5.1. Installation

To provision a server, Prospero requires following information:

- manifest definition

- location of channel’s Maven repositories

- server provisioning configuration

#### 5.1.1. Installing predefined server profile

Prospero provides a set of predefined profiles providing a simple way to install standard servers.

    $ ./prospero.sh install \
          --dir wfly-27 \
          --profile wildfly \
          --manifest /path/to/wildfly-manifest.yaml

The profile defines a feature-pack name and required repositories. It can also provide manifest information, if that manifest is published in a Maven repository.

#### 5.1.2. Installing a feature pack

If a desired server configuration is not provided by one of the profiles, Prospero can provision a feature pack based on its Maven coordinates (groupId:artifactId). The resulting server will have a default configuration provided by that feature pack.

    $ ./prospero.sh install \
          --dir wfly-27 \ # (1)
          --fpl org.wildfly:wildfly-ee-galleon-pack \ #(2)
          --manifest /path/to/wildfly-manifest.yaml \ #(3)
          --repositories https://repo1.maven.org/maven2/,https://repository.jboss.org/nexus/content/groups/public/ #(4)

1. directory to place provisioned server in

2. Maven `<groupId>:<artifactId>` coordinates of the feature pack to be installed

3. Path to the manifest file

4. List of Maven repositories containing components listed in the channel file.

Note | An example Wildfly manifest file is available in examples directory.

#### 5.1.3. Installing a customized feature pack

Galleon feature packs consist of layers and packages that can be excluded or included to generate customized server.

In order to create a customized installation, the required provisioning configuration need to be described in `provisioning.xml` file. For example, following file adds configuration examples to the generated server.

    <?xml version="1.0" ?>
    <installation xmlns="urn:jboss:galleon:provisioning:3.0">
        <feature-pack location="org.wildfly:wildfly-galleon-pack::zip">
          <packages>
            <include name="docs.examples.configs"/>
          </packages>
        </feature-pack>
    </installation>

The provisioning definition can then be used to create a server:

    $ ./prospero.sh install \
          --dir wfly-27 \
          --definition provisioning.xml \
          --manifest /path/to/wildfly-manifest.yaml
          --repositories https://repo1.maven.org/maven2/,https://repository.jboss.org/nexus/content/groups/public/

#### 5.1.4. Using offline or mirrored repositories

By default, any artifacts required to provision the server, will be resolved using public repositories. If the system on which the installation is performed doesn’t have access to the required repositories, alternative repositories need to provided using the `--repositories` argument.

The specified repositories can either be mirrors of public repositories, or local filesystem copies of the repositories. One way to generate such repository is installing the server on an online system using `--local-cache` argument:

    $ ./prospero.sh install \ #(1)
          --dir wfly-27 \
          --profile wildfly \
          --manifest /path/to/wildfly-manifest.yaml \
          --local-cache /path/to/local_repo

    $ ./prospero.sh install \ #(2)
          --dir offline-wfly-27 \
          --profile wildfly \
          --manifest /path/to/wildfly-manifest.yaml \
          --repositories /path/to/local_repo \
          --offline

1. Generates a repository at `/path/to/local_repo`

2. Installs the server using content of `/path/to/local_repo` instead of default repositories

Note | When using a <groupId>:<artifactId> to resolve manifest from a repository, the manifest artifact has to have accompanying Maven metadata (maven-metadata.xml).

#### 5.1.5. Selecting stability level of provisioned server

Some feature packs may contain experimental or preview features not intended to be made available by default. To separate those features from stable ones, feature packs may segregate the features into `stability-levels`. At the provisioning time, the user is able to change the default stability level of the feature pack by using the `--stability` flag.

    $ ./prospero.sh install \ #(1)
          --dir wfly-31 \
          --profile wildfly \
          --manifest /path/to/wildfly-manifest.yaml \
          --stability preview

For more fine-grained control, the level of installed packages and configuration can be set separately using `--config-stability` and `--package-stability` flags.

### 5.2. Update

Once the server is installed, it can receive updates published in the channels it is subscribed to.

Following command can be used to update the server using the subscribed channels:

    $ ./prospero.sh update perform --dir wfly-27

If any updates are available, Prospero will print the update summary and prompt for confirmation to continue. If the updates are accepted, the updated server will be prepared in a way described in Update process.

Note | The server has to be stopped during `update perform` operation

#### 5.2.1. Checking updates

`prospero update list` command can be used to check if any updates are available:

    $ ./prospero.sh update list --dir wfly-27

#### 5.2.2. Working with update candidates

When using `prospero update perform` command, the server has to be stopped during the whole update process. In order to reduce server downtime, it is possible to generate an update candidate while the server is running and apply it to a stopped server in a separate step.

    $ ./wfly-27/bin/standalone.sh > /dev/null & # (1)

    $ ./prospero.sh update prepare \ # (2)
           --dir wfly-27 \
           --candidate-dir candidate-dir \
           --yes

    $ ./wfly-27/bin/jboss-cli.sh -c "shutdown" # (3)

    $ ./prospero.sh update apply \ # (4)
           --dir wfly-27 \
           --candidate-dir candidate-dir

1. start the server in background

2. generate the candidate in `candidate-dir` folder

3. stop the server

4. merge the updates found in `candidate-dir` into `wfly-27` server

Update candidate is a temporary server provisioned by prospero. It is generated using the latest updates available in the channels, but does not contain any user modifications of the original server.

Note | The candidate can only be applied to a server it was based on and only if the server has not been updated since the candidate was generated.

#### 5.2.3. Using alternative repository

If the repositories defined in subscribed channels are not available to the server, alternative repositories can be provided using `--repositories` parameter. Those repositories can point to a local copy of the repository or alternate online location.

    $ ./prospero.sh update perform \
           --dir wfly-27 \
           --repositories https://proxy.corp.org/maven-central # (1)

1. The updates will be resolved from https://proxy.corp.org/maven-central instead of the default repository.

The `--repositories` can also be used to resolve artifact from a local copy of the repository:

    $ ./prospero.sh update perform \
           --dir wfly-27 \
           --repositories /path/to/repository

Note | At minimum, the alternative repositories have to provide all the channel manifests that the server is subscribed to and updated artifacts.

#### 5.2.4. Subscribing existing server

Prospero relies on additional metadata files being present in the server installation to provide updates. Using `update subscribe` command it is possible to generate required files in a server.

    $ ./prospero.sh update subscribe \
           --dir wfly-27 \
           --product=wildfly \ # (1)
           --version=29.0.1.Final # (2)

1. name of the installed server, or name of the feature pack used to install the server

2. version of installed server or feature pack

The product and version information is needed to determine currently installed software and subscribe server to correct channels.

### 5.3. Channel management

The server subscribes to the channels to receive updates from them. The list of subscriptions can be managed using `prospero channel` subcommands.

#### 5.3.1. Listing channels

Command `prospero channel list` prints a summary of subscribed channels.

    $ ./prospero.sh channel list --dir wfly-27
    Server /tmp/wfly-27 is subscribed to following channels:

    -------
    # channel-0
      manifest: org.wildfly.channel:wfly-27
      repositories:
        id: central
        url: https://repo1.maven.org/maven2/
    -------

#### 5.3.2. Subscribing to a channel

Command `prospero channel add` subscribes the server to receive updates from additional channels. Each channel has to have a unique name, a manifest and a list of repositories. The channel’s artifacts will be used to resolve artifacts during next `update`.

    $ ./prospero.sh channel add \
       --channel-name dev-channel \
       --manifest org.prospero.channel:wfly-27-dev \ # (1)
       --repositories file:/tmp/dev-repository \ # (2)
       --dir wfly-27
    Subscribing /tmp/wfly-27 to channel dev-channel

    Channel 'dev-channel' added.

1. The Maven coordinates (groupId:artifactId) of the new channel’s manifest

2. The Maven repository where the manifest and artifacts can be found in

#### 5.3.3. Unsubscribing from a channel

Command `channel remove` unsubscribes the server from a selected channel, stopping it from receiving updates from that channel. The artifacts previously installed from that channel will be replaced with artifacts available in remaining channel during next `update` operation.

    $ ./prospero.sh channel remove \
       --channel-name dev-channel \
       --dir installation-dir
    Unsubscribing /tmp/wfly-27 from channel dev-channel

    Channel 'dev-channel' removed.

### 5.4. Update history

Each time the server is updated, the previous state of the server is recorded. That state includes the channels used to perform the update and the versions of artifacts used to build the server.

This information is used to restore the server back to past state.

#### 5.4.1. Viewing history

Command `history` displays a list of all server updates:

    $ ./prospero.sh history --dir wfly-27
    [02805caa] 2023-05-25T15:07:19Z - update [org.wildfly.channel:wfly-27::1.0.1]
    [c5215591] 2023-05-25T15:05:04Z - install [org.wildfly.channel:wfly-27::1.0.0]

The server state record contains following information: a hash identifier, date of the change, type of the change (installation, update, configuration change) and a summary of channel manifests used in that update.

The details of each record can be examined using `--revision` parameter:

    $ ./prospero.sh history --dir wfly-27 --revision 02805caa
    Updates:
      [Updated artifact] io.undertow:undertow-servlet:		2.2.18.Final ==> 2.2.19.Final
      [Updated artifact] io.undertow:undertow-websockets-jsr:		2.2.18.Final ==> 2.2.19.Final
      [Updated artifact] io.undertow:undertow-core:		2.2.18.Final ==> 2.2.19.Final

#### 5.4.2. Reverting updates

The server can be reverted to any of the recorded states. The `revert` commands operate in similar way to `update`. For example, a following command performs a full revert of a server to an earlier installation state:

    $ ./prospero.sh revert perform --dir wfly-27 --revision c5215591
    Reverting server /tmp/wfly-27 to state c5215591

    Feature-packs resolved.
    Packages installed.
    Downloaded artifacts.
    JBoss modules installed.
    Configurations generated.

    Reverted server prepared, comparing changes
    Changes found:
      io.undertow:undertow-servlet                          2.2.19.Final         ==>  2.2.18.Final
      io.undertow:undertow-websockets-jsr                   2.2.19.Final         ==>  2.2.18.Final
      io.undertow:undertow-core                             2.2.19.Final         ==>  2.2.18.Final
    Continue with revert [y/N]: y
    Applying changes

    Server reverted to state 348b9d9c.
    Operation completed in 45.83 seconds.

The revert process works similar to the update process, but instead of resolving component versions from subscribed channels, the component versions recorded in the requested state will be used.

Note | The required components will be downloaded from the channel repositories the server was subscribed to at the requested state. If the channel repositories are no longer available, or do not provide the required component versions, `--repositories` can be used to overwrite them.

Note | The server has to be switched off for the duration of the `revert perform` operation.

#### 5.4.3. Reverting updates using candidate

Similarly to `update` operation, the `revert` operation can be split into preparing the candidate and applying the changes. In such case, the server downtime is only required during the latter phase.

    $ ./prospero.sh revert prepare \ #(1)
        --candidate-dir candidate \
        --revision c5215591 \
        --dir wfly-27
    Building revert candidate for /tmp/wfly-27

    Feature-packs resolved.
    Packages installed.
    Downloaded artifacts.
    JBoss modules installed.
    Configurations generated.

    Update candidate generated in /Users/spyrkob/workspaces/set/prospero/prospero/candidate
    Operation completed in 22.22 seconds.

    $  ./prospero.sh revert apply \ #(2)
        --dir wfly-27 \
        --candidate-dir candidate
    Reverting server /tmp/wfly-27 to state ab39b0c6

    Changes found:
      io.undertow:undertow-servlet                          2.2.19.Final         ==>  2.2.18.Final
      io.undertow:undertow-websockets-jsr                   2.2.19.Final         ==>  2.2.18.Final
      io.undertow:undertow-core                             2.2.19.Final         ==>  2.2.18.Final
    Continue with revert [y/N]: y
    Applying changes

    Server reverted to state ab39b0c6.
    Operation completed in 9.40 seconds.

1. Prepare a revert candidate in `candidate` folder

2. Apply prepared `candidate` to a server in `wfly-27`

### 5.5. Replicating installation

Sometimes it might be needed to provision a copy of the server, with the same components as the original, in a different environment. To achieve that, Prospero requires following information:

- a list of component versions used to provision the server,

- a list of channels used during provisioning,

- a list of Galleon feature packs used.

This information can be obtained from any provisioned server using `clone export` command:

    $ ./prospero.sh clone export --dir wfly-27 --path snapshot.zip
    Exporting /tmp/wfly-27 installation details to /tmp/snapshot.zip
    Export complete

The generated archive contains following files:

    Archive:  snapshot.zip
      Length      Date    Time    Name
    ---------  ---------- -----   ----
        68301  05-26-2023 15:59   manifest.yaml
          476  05-26-2023 15:59   installer-channels.yaml
          606  05-26-2023 15:59   provisioning.xml
    ---------                     -------
        69383                     3 files

The archive can be used to rebuild the server:

    $ ./prospero clone recreate --dir cloned --path export.zip
    Recreating a server in /tmp/cloned based on /tmp/export.zip

    Provisioning configuration:
     * org.wildfly:wildfly-galleon-pack:zip
    Subscribed channels:
    # wildfly
      manifest: org.wildfly.channel:wfly-27
      repositories:
        id: central
        url: https://repo1.maven.org/maven2/
        id: jboss-public
        url: https://repository.jboss.org/nexus/content/groups/public/
        id: mrrc
        url: https://maven.repository.redhat.com/ga/
        id: local-repo
        url: file:/Users/spyrkob/workspaces/set/prospero/prospero/test-repo

    Feature-packs resolved.
    Packages installed.
    Downloaded artifacts.
    JBoss modules installed.
    Configurations generated.

    Server installation was restored.
    Operation completed in 28.12 seconds.

Note | The user changes made to the original server are not applied to the clone.

### 5.6. Installing additional Galleon Feature Packs

Galleon feature packs can be used to extend capabilities offered by base server and provide features like, for example, datasource support or alternative JSF implemetnation.

Prospero allows users to install such feature pack on top of existing server using `feature-pack add` operation.

#### 5.6.1. Feature pack channels

As with all the components used to provision the server, Prospero relies on channels to supply the feature pack and any artifacts it may require. In some cases the base server channel may offer the additional feature packs, in others, an additional channel will have to be registered with the server. See Subscribing to a channel for information how to subscribe to a channel.

Sometimes feature packs may require additional artifacts whose lifecycle is separate from the feature pack itself. For example, Datasources feature pack lets users specify which version of database driver should be installed irrespective of the feature pack version. In such cases users have to create and subscribe to a new channel providing those artifacts.

For example, a channel supplying Datasources feature pack could use Maven Central repository and a following manifest:

    schemaVersion: 1.0.0
    streams:
      - groupId: org.wildfly
        artifactId: wildfly-datasources-galleon-pack
        version: 4.0.1.Final
      - groupId: com.mysql
        artifactId: mysql-connector-j
        version: 8.1.0

#### 5.6.2. Installing feature pack

The feature packs are identified by GroupId:ArtifactId part of their Maven coordinates. This is known as their Feature Pack Location (fpl).

For example, assuming the server is subscribed to a datasources channel, following command will install the datasources feature pack:

    $ prospero feature-pack add \
      --fpl org.wildfly:wildfly-datasources-galleon-pack \
      --dir wildfly

Note | This specific command does not in fact install any database drivers or datasources. See further examples bellow to see how to specify drivers and datasources to install or refer to wildfly-datasources documentation.

#### 5.6.3. Customizing installed feature packs

The Galleon feature packs may provide different capabilities using layers. Users may select a set of layers to install using `--layers` parameter.

If the feature pack changes server configuration files, the user may also choose which server configuration should be affected using `--target-config` parameter. If not provided, the layer configuration will use default values. Most Wildfly feature packs provide only a single model (standalone) and the default configuration file of standalone.xml.

Note | If the affected configuration file has been modified by the user, that file will not be modified. Instead, a new configuration file with suffix `.glnew` will be created with the changes.

Note | Some feature packs do not allow customization of layers or selected configuration files. Those feature packs have to be installed without `--layers` or `--target-config` parameters.

For example to install mysql support and configure the datasource in Wildfly `standalone-full.xml` configuration file, a following command can be used:

    $ prospero feature-pack add \
      --fpl org.wildfly:wildfly-datasources-galleon-pack \
      --layers=mysql-datasource \
      --target-config=standalone-full.xml \
      --dir wildfly

If the feature pack provides multiple configuration model, the configuration name can be prefixed with model name e.g. `--target-config standalone/standalone.xml`

#### 5.6.4. Offline installation

Similarly to other operations, `feature-pack add` can be executed in an offline mode. To do so, users should provide local repositories with all required artifacts (both for base server and the new feature) using `--repositories` parameter.

#### 5.6.5. Installation history

Installing a feature pack is recorded in the server history as feature_add event. Displaying the feature_add revision shows details of installed feature pack:

    ./prospero history --dir installation-dir  --revision f7488855
    Updates:
      [Added artifact] org.wildfly:wildfly-datasources-galleon-pack:		[] ==> 4.0.1.Final

    Installed features changes:
      [Added Feature Pack] org.wildfly:wildfly-datasources-galleon-pack::zip@maven

## 6. Custom channels

Sometimes a server needs to be updated with different versions of components than other servers. To achieve that, a server can subscribe to a custom channel on top of its normal channels. This channel will define modified versions of components.

For example if the main channel defines component `foo:bar:1.2.3`, the custom channel could contain `foo:bar:1.2.3-patch0001`. During any update operations, the most recent version of the `foo:bar` across both channels will be applied to the server.

The custom channel needs to be hosted in a Maven repository - either a local filesystem repository on the same system as the server, or a web repository shared between a group of servers. The repository is used to host a versioned channel definition and all customized artifacts.

### 6.1. Custom artifact versioning

When multiple versions of the same artifact are available from different channels, Prospero will always choose the latest available version of this artifact.

Therefore, the customized artifacts have to always have higher versions than artifacts they are replacing. For instance, if a server includes `my:artifact:1.1.0`, the customization channel can provide a version `my:artifact:1.1.0-path-00001` or `my:artifact:1.1.1`, but not `my:artifact:1.0.9`.

### 6.2. Register custom channel

In order for the server to receive updates from a custom channel, the server needs to be subscribed to the channel and associated repositories.

The channel can be hosted either in an internal installation repository, serving a single server or in a shared repository. To configure the server with a custom channel following commands can be used:

Single server channel

    prospero channel add \
      --channel-name customizations \
      --repositories file:/path/to/local/repository \
      --manifest org.wildfly.prospero:customizations

A server can use a filesystem repository and auto-generated channel to provide customizations. This command will register the server to recieve updates from a Maven repository in `/path/to/local/repository` folder.

The customized artifacts should be listed in a manifest file deployed to the above repository as `org.wildfly.prospero:customizations:manifest:yaml:<VERSION>`

Shared channel

An online repository can be used to distribute the customizations among multiple servers. Each server has to be subscribed to the repository using:

    prospero channel add \
      --channel-name customizations \
      --repositories http://repository.host/path \
      --manifest=org.wildfly.prospero:customizations

Note | The repository can be used to host customizations applicable to a different group of servers. In that case each set of customizations would have a separate manifest deployed under unique Maven `groupId:artifactId` coordinates.

### 6.3. Distributing custom artifacts

The customized artifacts can be distributed as bundles. Each bundle is a ZIP archive containing a `maven-repository` directory and an optional `artifact-list.yaml` file.

    |-artifact-list.yaml
    |-maven-repository
      |- org
        |-custom
          |-artifact-one
            |-1.2.3
              |-artifact-one-1.2.3.jar
          |-artifact-two
            |-2.3.4
              |-artifact-two-2.3.4.jar
        |-wildfly
          |-prospero
            |-customizations
              |-1.0.0
                |-customizations-manifest-1.0.0.yaml
              |-maven-metadata.xml

In addition to the custom artifacts, repository has to contain a channel manifest. The manifest should list all streams available in the customization bundle.

    schemaVersion: 1.0.0
    name: Customizations manifest
    streams:
      - groupId: org.custom
        artifactId: artifact-one
        version: 1.2.3
      - groupId: org.custom
        artifactId: artifact-two
        version: 2.3.4

Note | the Maven metadata has to be present for the manifest artifact.

The `artifact-list.yaml` lists all artifacts included in the bundle using following syntax:

    artifacts:
      - groupId: "org.custom"
        artifactId: "artifact-one"
        version: "1.2.3"
        packaging: "jar"
        extension: ""

#### 6.3.1. Updating custom artifacts

If a new version of customization bundle needs to be distributed, it should contain a customization manifest deployed under the same `groupId:artifactId` coordinates, but with an incremented version.

The repository should contain all customized artifacts required by the updated manifest. For instance, the updated manifest included a new version of `artifact-one` and added `artifact-three`, resulting in following file:

    schemaVersion: 1.0.0
    name: Customizations manifest
    streams:
      - groupId: org.custom
        artifactId: artifact-one
        version: 1.2.4
      - groupId: org.custom
        artifactId: artifact-two
        version: 2.3.4
      - groupId: org.custom
        artifactId: artifact-three
        version: 3.4.5

The updated repository should contain three artifacts:

    |-artifact-list.yaml
    |-maven-repository
      |- org
        |-custom
          |-artifact-one
            |-1.2.4
              |-artifact-one-1.2.4.jar
          |-artifact-two
            |-2.3.4
              |-artifact-two-2.3.4.jar
          |-artifact-three
            |-3.4.5
              |-artifact-two-3.4.5.jar
        |-wildfly
          |-prospero
            |-customizations
              |-1.0.1
                |-customizations-manifest-1.0.1.yaml
              |-maven-metadata.xml

### 6.4. Promoting custom artifacts

To make the custom artifact available to registered servers, the update artifacts from the customization bundle have to be added to the existing repository.

The updated artifacts are distributed in a `maven-repository` folder inside the customization archive. If the server is subscribed to a local filesystem customization repository, all the artifacts can be simply copied over.

    $ ./prospero.sh channel list
    # customizations
      manifest: org.wildfly.prospero:customizations
      repositories:
        id: custom-repo-0
        url: file:/home/wildfly/custom/repository # (1)

    $ unzip customization-1.0.1.zip # (2)
    Archive:  customization-1.0.1.zip
       creating: customization/
       inflating: artifact-list.yaml
       creating: customization/maven-repository/
       [...]

    $ cp -r customization/maven-repositry/* /home/wildfly/custom/repository/ #(3)

    $ ./prospero.sh updates perform #(4)

1. Location of existing customization repository

2. Extracting updated repository

3. Adding updated content to existing repository

4. Apply updated customizations

If a repository manager like Nexus is used to host the customization repository, the artifacts should be deployed into it.

Warning | When promoting different versions of the same customization bundle, older versions of the bundle should never be promoted after a newer version is promoted. The customization repository contains `maven-metadata.xml` files associated with the customization’s manifest that would be overwritten by such operation.

### 6.5. Apply changes to the server

After promoting artifacts to the channel, the changes can be applied to subscribed servers.

Promoted changes are treated as any updates, so `prospero update` command can be used to apply them.

    prospero update --dir=<PATH/TO/SERVER>
    Feature-packs resolved.
    Updates found:
      foo:bar                             1.2.3         ==>  1.2.3-patch0001

Note | During update, the latest artifacts available in all registered channels are chosen. If the main channel is updated with newer version of artifact then available in the custom channel, the customized artifact will be removed from the server.

## 7. Working with channels

More information on the Wildfly Channels can be found in https://github.com/wildfly-extras/wildfly-channel/blob/main/doc/spec.adoc. This chapter is intended to explain some concepts behind different channel types and how they can be used to provide software updates.

A channel contains a collections of artifact streams used by a server. Each stream should contain only backwards-compatible artifact updates with new versions of artifacts replacing previous ones.

There are two ways for a stream to determine the versions of its artifact:

- using an artifact manifest with fixed versions, or

- use the latest artifact version available in backing Maven repository.

Note | The two mechanisms can be mixed within one channel, using static list to resolve some streams and Maven metadata for others.

Channels using exclusively fixed version manifest can be more stable and make it possible to use 3rd party repositories. The artifact combination in the manifest can be tested before distributing, making sure there are no regressions.

On the other hand channels using Maven metadata can make development and testing of new component updates easier. Any component updates deployed into the Maven repository are immediately made available to the subscribed servers.

### 7.1. Channels with fixed version manifests

This kind of channels rely on manifests to list all available artifacts and their versions. This can be useful when the content of the repository cannot be fully controlled and might contain incompatible artifact versions.

The manifest is a YAML file, containing a list of available streams:

manifest.yaml

    schemaVersion: "1.0.0"
    name: "test-manifest"
    streams:
      - groupId: "org.test"
        artifactId: "artifact-one"
        version: "1.2.0.Final"

The manifest has to be deployed in the channel repository and registered in the channel definition:

channel.yaml

    schemaVersion: "2.0.0"
    name: "test-channel"
    resolve-if-no-stream: none #(1)
    repositories:
      - id: "trusted"
        url: "https://trusted.repository.org/maven/"
    manifest:
      maven:
        groupId: org.test.channel
        artifactId: test-manifest

1. this channel provides only artifacts explicitly listed in the manifest

#### 7.1.1. Updating components in fixed version channel

Updating a component in a manifest channel requires publishing a new version of manifest.

For example, if the `org.test:artifact-one` is updated to `1.2.1.Final` version, the new manifest would look like as follows:

manifest.yaml

    schemaVersion: "1.0.0"
    name: "test-manifest"
    streams:
      - groupId: "org.test"
        artifactId: "artifact-one"
        version: "1.2.1.Final"

This manifest has to be published in the channel repository with a new version:

    mvn deploy:deploy-file -Dfile=manifest.yaml \
    -DgroupId=org.test.channels -DartifactId=test-manifest \
    -Dversion=1.0.1 \ #(1)
    -Dclassifier=manifest -Dpackaging=yaml \
    -Durl=https://trusted.repository.org/maven/

1. note the updated version

There are no changes required to the channel definition. Next time components are resolved from this channel, a new version of manifest will be used providing version 1.2.1.Final of `org.test:artifact-one`.

### 7.2. Channels using backing Maven repository versions

This type of channels expose the latest available versions of artifacts found in their repositories as the component version. The versions can be curated using either version patterns or a blocklist excluding specific versions.

Channels based on Maven metadata can be useful when the content of repositories can be controlled and trusted. Any new artifact deployed into the channel repository, will automatically be made available for subscribed servers.

An example of channel exposing all underlying artifacts can be seen below:

channel.yaml

    schemaVersion: "2.0.0"
    name: "test-channel"
    resolve-if-no-stream: latest #(1)
    repositories: #(2)
      - id: "trusted"
        url: "https://trusted.repository.org/maven/"

1. `latest` strategy means that if channel cannot find a stream matching the requested artifact, it will attempt to find the latest version in its repositories

2. the underlying repository for the channel

#### 7.2.1. Using version patterns to limit artifacts

Sometimes the underlying repository might contain versions of artifacts that are not compatible with the installed server. For example the server might require a 1.2.x version of a certain artifact, but the repository contains a newer version 2.0.x.

To filter incompatible versions, the channel can use a manifest file with `versionPattern` streams.

manifest.yaml

    schemaVersion: "1.0.0"
    name: "test-manifest"
    streams:
      - groupId: "org.test"
        artifactId: "artifact-one"
        versionPattern: "1\\.2\\..*" #(1)

1. a regular expression limiting versions to ones starting with `1.2.`

Note | The `versionPattern` field uses regular expressions

The above manifest file should be deployed in the channel repository with a classifier `manifest` and extension `yaml`. For example following command will deploy the file as `org.test.channels:test-manifest:1.0.0`

    mvn deploy:deploy-file -Dfile=manifest.yaml \
      -DgroupId=org.test.channels -DartifactId=test-manifest \
      -Dversion=1.0.0 -Dclassifier=manifest -Dpackaging=yaml \
      -Durl=https://trusted.repository.org/maven/

The channel definition needs to be updated to reference the new manifest file:

channel.yaml

    schemaVersion: "2.0.0"
    name: "test-channel"
    resolve-if-no-stream: latest
    repositories:
      - id: "trusted"
        url: "https://trusted.repository.org/maven/"
    manifest:
      maven:
        groupId: org.test.channel
        artifactId: test-manifest

Using this channel definition, all artifacts apart from `org.test:artifact-one` are still resolved to the latest versions available in the repository. The `org.test:artifact-one` will be resolved to the latest available "1.2.x" micro version. For example, if the repository contains versions [1.2.0.Final, 1.2.1.Final, 2.0.0.Final], the channel will pick version 1.2.1.Final.

#### 7.2.2. Creating blocklist to exclude updates

Another option to exclude certain artifact versions is to use a blocklist. A blocklist is a YAML file deployed in the channel repository listing blocked artifact versions.

blocklist.yaml

    schemaVersion: "1.0.0"
    name: "test-blocklist"
    blocks:
      - groupId: "org.test"
        artifactId: "artifact-one"
        versions:
        - "1.2.2.Final"

Again, the blocklist has to be deployed in the channel repository. The blocklist artifact has to use `blocklist` classifier and `yaml` extension. For example:

    mvn deploy:deploy-file -Dfile=blocklist.yaml \
      -DgroupId=org.test.channels -DartifactId=test-blocklist \
      -Dversion=1.0.0 -Dclassifier=blocklist -Dpackaging=yaml \
      -Durl=https://trusted.repository.org/maven/

Finally, the channel definition has to be updated with the reference to the blocklist:

channel.yaml

    schemaVersion: "2.0.0"
    name: "test-channel"
    resolve-if-no-stream: latest
    blocklist:
      maven:
        groupId: org.test.channel
        artifactId: test-blocklist
    repositories:
      - id: "trusted"
        url: "https://trusted.repository.org/maven/"
    manifest:
      maven:
        groupId: org.test.channel
        artifactId: test-manifest

Resolving `org.test:artifact-one` from this channel will exclude any versions not matching "1.2." pattern and version 1.2.2.Final. For example, if the repository contains versions [*1.2.0.Final, 1.2.1.Final, 1.2.2.Final, 2.0.0.Final], the channel will pick version 1.2.1.Final.

#### 7.2.3. Updating components using "open" channel

Updating component in an open channel requires only deploying the artifact into the channel repository. Neither channel definition not channel manifest has to be changed. Next time components are resolved from this channel, a new version of updated component will be used.