Chapter 1. Customizing the devfile and plug-in registries CodeReady Workspaces 2.1 introduces two registries: the plug-ins registry and the devfile registry. They are static websites where the metadata of CodeReady Workspaces plug-ins and CodeReady Workspaces devfiles is published. The plug-in registry makes it possible to share a plug-in definition across all the users of the same instance of CodeReady Workspaces. Only plug-ins that are published in a registry can be used in a devfile. The devfile registry holds the definitions of the CodeReady Workspaces stacks. These are available on the CodeReady Workspaces user dashboard when selecting Create Workspace . It contains the list of CodeReady Workspaces technological stack samples with example projects. The devfile and plug-in registries run in two separate pods and are deployed when the CodeReady Workspaces server is deployed (that is the default behavior of the CodeReady Workspaces Operator). The metadata of the plug-ins and devfiles are versioned on GitHub and follow the CodeReady Workspaces server life cycle. In this document, the following two ways to customize the default registries that are deployed with CodeReady Workspaces (to modify the plug-ins or devfile metadata) are described: Building a custom image of the registries Running the default images but modifying them at runtime Building and running a custom registry image Including the plug-in binaries in the registry image Editing a devfile and plug-in at runtime 1.1. Building and running a custom registry image This section describes the building of registries and updating a running CodeReady Workspaces server to point to the registries. 1.1.1. Building a custom devfile registry This section describes how to build a custom devfiles registry. Following operations are covered: Getting a copy of the source code necessary to build a devfiles registry. Adding a new devfile. Building the devfiles registry. Procedure Clone the devfile registry repository: In the ./che-devfile-registry/devfiles/ directory, create a subdirectory <devfile-name> / and add the devfile.yaml and meta.yaml files. File organization for a devfile Add valid content in the devfile.yaml file. For a detailed description of the devfile format, see the Making a workspace portable using a devfile section. Ensure that the meta.yaml file conforms to the following structure: Table 1.1. Parameters for a devfile meta.yaml Attribute Description description Description as it appears on the user dashboard. displayName Name as it appears on the user dashboard. globalMemoryLimit The sum of the expected memory consumed by all the components launched by the devfile. This number will be visible on the user dashboard. It is informative and is not taken into account by the CodeReady Workspaces server. icon Link to an .svg file that is displayed on the user dashboard. tags List of tags. Tags usually include the tools included in the stack. Example devfile meta.yaml displayName: Rust description: Rust Stack with Rust 1.39 tags: ["Rust"] icon: https://www.eclipse.org/che/images/logo-eclipseche.svg globalMemoryLimit: 1686Mi Build the containers for the custom devfile registry: 1.1.2. Building a custom plug-in registry This section describes how to build a custom plug-in registry. Following operations are covered: Getting a copy of the source code necessary to build a custom plug-in registry. Adding a new plug-in. Building the custom plug-in registry. Procedure Clone the plug-in registry repository: In the ./che-plugin-registry/v3/plugins/ directory, create new directories <publisher> / <plugin-name> / <plugin-version> / and a meta.yaml file in the last directory. File organization for a plugin Add valid content to the meta.yaml file. See the "Using a Visual Studio Code extension in CodeReady Workspaces" section or the README.md file in the eclipse/che-plugin-registry repository for a detailed description of the meta.yaml file format. Create a file named latest.txt with content the name of the latest <plugin-version> directory. Example Build the containers for the custom plug-in registry: 1.1.3. Deploying the registries Prerequisites The my-plug-in-registry and my-devfile-registry images used in this section are built using the docker command. This section assumes that these images are available on the OpenShift cluster where CodeReady Workspaces is deployed. This is true on Minikube, for example, if before running the docker build commands, the user executed the eval USD\{minikube docker-env} command (or, the eval USD\{minishift docker-env} command for Minishift). Otherwise, these images can be pushed to a container registry (public, such as quay.io , or the DockerHub, or a private registry). 1.1.3.1. Deploying registries in OpenShift Procedure An OpenShift template to deploy the plug-in registry is available in the openshift/ directory of the GitHub repository. To deploy the plug-in registry using the OpenShift template, run the following command: 1 If installed using crwctl, the default CodeReady Workspaces namespace is workspaces . The OperatorHub installation method deploys CodeReady Workspaces to the users current namespace. The devfile registry has an OpenShift template in the deploy/openshift/ directory of the GitHub repository. To deploy it, run the command: 1 If installed using crwctl, the default CodeReady Workspaces namespace is workspaces . The OperatorHub installation method deploys CodeReady Workspaces to the users current namespace. Check if the registries are deployed successfully on OpenShift. To verify that the new plug-in is correctly published to the plug-in registry, make a request to the registry path /v3/plugins/index.json (or /devfiles/index.json for the devfile registry). Verify that the CodeReady Workspaces server points to the URL of the registry. To do this, compare the value of the CHE_WORKSPACE_PLUGIN__REGISTRY__URL parameter in the codeready ConfigMap (or CHE_WORKSPACE_DEVFILE__REGISTRY__URL for the devfile registry): with the URL of the route: If they do not match, update the ConfigMap and restart the CodeReady Workspaces server. When the new registries are deployed and the CodeReady Workspaces server is configured to use them, the new plug-ins are available in the Plugin view of a workspace and the new stacks are displayed in the New Workspace tab of the user dashboard. 1.2. Including the plug-in binaries in the registry image The plug-in registry only hosts CodeReady Workspaces plug-in metadata. The binaries are usually referred through a link in the meta.yaml file. Sometimes, such as offline environments, it may be necessary to make the binaries available inside the registry image. This section describes how to modify a plug-in meta.yaml file to point to a local file inside the container and rebuild a new registry that contains the modified plug-in meta.yaml file and the binary file. In the following example, the Java plug-in that refers to two remote VS Code extensions binaries is considered. Prerequisites CodeReady Workspaces is installed. The OpenShift command-line tool, oc , is installed. Procedure Download the binaries locally: Get the plug-in registry URL: For an Operator installation: Note that the obtained URL is without the http or https prefix. Update the URLs in the meta.yaml file, so that they point to the VS Code extension binaries that are saved in the registry container: Build and deploy the plug-in registry using the instructions in the Building and running a custom registry image section. 1.3. Editing a devfile and plug-in at runtime An alternative to building a custom registry image is to: Start a registry Modify its content at runtime This approach is simpler and faster. But the modifications are lost as soon as the container is deleted. 1.3.1. Adding a plug-in at runtime Procedure To add a plug-in: Check out the plugin registry sources. Create a meta.yaml in some local folder. This can be done from scratch or by copying from an existing plug-in's meta.yaml file. If copying from an existing plug-in, make changes to the meta.yaml file to suit your needs. Make sure your new plug-in has a unique title , displayName and description . Update the firstPublicationDate to today's date. These fields in meta.yaml must match the path defined in PLUGIN above. Get the name of the Pod that hosts the plug-in registry container. To do this, filter the component=plugin-registry label: Regenerate the registry's index.json file to include your new plug-in. Copy the new index.json and meta.yaml files from your new local plug-in folder to the container. The new plug-in can now be used from the existing CodeReady Workspaces instance's plug-in registry. To discover it, go to the CodeReady Workspaces dashboard, then click the Workspaces link. From there, click the gear icon to configure one of your workspaces. Select the Plugins tab to see the updated list of available plug-ins. 1.3.2. Adding a devfile at runtime Procedure To add a devfile: Check out the devfile registry sources. Create a devfile.yaml and meta.yaml in some local folder. This can be done from scratch or by copying from an existing devfile. If copying from an existing devfile, make changes to the devfile to suit your needs. Make sure your new devfile has a unique displayName and description . Get the name of the Pod that hosts the devfile registry container. To do this, filter the component=devfile-registry label: Regenerate the registry's index.json file to include your new devfile. Copy the new index.json , devfile.yaml and meta.yaml files from your new local devfile folder to the container. The new devfile can now be used from the existing CodeReady Workspaces instance's devfile registry. To discover it, go to the CodeReady Workspaces dashboard, then click the Workspaces link. From there, click Add Workspace to see the updated list of available devfiles.

Commands:
git clone git@github.com:redhat-developer/codeready-workspaces.git cd codeready-workspaces/dependencies/che-devfile-registry
./che-devfile-registry/devfiles/ └── <devfile-name> ├── devfile.yaml └── meta.yaml
displayName: Rust description: Rust Stack with Rust 1.39 tags: ["Rust"] icon: https://www.eclipse.org/che/images/logo-eclipseche.svg globalMemoryLimit: 1686Mi
docker build -t my-devfile-registry .
git clone git@github.com:redhat-developer/codeready-workspaces.git cd codeready-workspaces/dependencies/che-plugin-registry
./che-plugin-registry/v3/plugins/ ├── <publisher> │ └── <plugin-name> │ ├── <plugin-version> │ │ └── meta.yaml │ └── latest.txt
tree che-plugin-registry/v3/plugins/redhat/java/ che-plugin-registry/v3/plugins/redhat/java/ ├── 0.38.0 │ └── meta.yaml ├── 0.43.0 │ └── meta.yaml ├── 0.45.0 │ └── meta.yaml ├── 0.46.0 │ └── meta.yaml ├── 0.50.0 │ └── meta.yaml └── latest.txt cat che-plugin-registry/v3/plugins/redhat/java/latest.txt 0.50.0
docker build -t my-devfile-registry .
NAMESPACE= <namespace-name> 1 IMAGE_NAME="my-plug-in-registry" IMAGE_TAG="latest" new-app -f openshift/che-plugin-registry.yml -n "USD\{NAMESPACE}" -p IMAGE="USD\{IMAGE_NAME}" -p IMAGE_TAG="USD\{IMAGE_TAG}" -p PULL_POLICY="IfNotPresent"
NAMESPACE= <namespace-name> 1 IMAGE_NAME="my-devfile-registry" IMAGE_TAG="latest" new-app -f openshift/che-devfile-registry.yml -n "USD\{NAMESPACE}" -p IMAGE="USD\{IMAGE_NAME}" -p IMAGE_TAG="USD\{IMAGE_TAG}" -p PULL_POLICY="IfNotPresent"
URL=USD(oc get -o 'custom-columns=URL:.spec.rules[0].host' -l app=che-plugin-registry route --no-headers) INDEX_JSON=USD(curl -sSL http://USD{URL}/v3/plugins/index.json) echo USD{INDEX_JSON} | grep -A 4 -B 5 "\"name\":\"my-plug-in\"" ,\{ "id": "my-org/my-plug-in/1.0.0", "displayName":"This is my first plug-in for CodeReady Workspaces", "version":"1.0.0", "type":"VS Code extension", "name":"my-plug-in", "description":"This plugin shows that we are able to add plugins to the registry", "publisher":"my-org", "links": \{"self":"/v3/plugins/my-org/my-plug-in/1.0.0" } } -- -- ,\{ "id": "my-org/my-plug-in/latest", "displayName":"This is my first plug-in for CodeReady Workspaces", "version":"latest", "type":"VS Code extension", "name":"my-plug-in", "description":"This plugin shows that we are able to add plugins to the registry", "publisher":"my-org", "links": \{"self":"/v3/plugins/my-org/my-plug-in/latest" } }
oc get -o "custom-columns=URL:.data['CHE_WORKSPACE_PLUGIN REGISTRY URL']" --no-headers cm/che URL http://che-plugin-registry-che.192.168.99.100.mycluster.mycompany.com/v3
oc get -o 'custom-columns=URL:.spec.rules[0].host' -l app=che-plugin-registry route --no-headers che-plugin-registry-che.192.168.99.100.mycluster.mycompany.com
oc edit cm/che (...) oc scale --replicas=0 deployment/che oc scale --replicas=1 deployment/che
ORG=redhat NAME=java11 VERSION=latest URL_VS_CODE_EXT1="https://github.com/microsoft/vscode-java-debug/releases/download/0.19.0/vscode-java-debug-0.19.0.vsix[_https://github.com/microsoft/vscode-java-debug/releases/download/0.19.0/vscode-java-debug-0.19.0.vsix_]" URL_VS_CODE_EXT2="https://download.jboss.org/jbosstools/static/jdt.ls/stable/java-0.46.0-1549.vsix[_https://download.jboss.org/jbosstools/static/jdt.ls/stable/java-0.46.0-1549.vsix_]" VS_CODE_EXT1=https://github.com/microsoft/vscode-java-debug/releases/download/0.19.0/vscode-java-debug-0.19.0.vsix[_vscode-java-debug-0.19.0.vsix_] VS_CODE_EXT2=https://download.jboss.org/jbosstools/static/jdt.ls/stable/java-0.46.0-1549.vsix[_java-0.46.0-1549.vsix_] curl -sSL -o ./che-plugin-registry/v3/plugins/USD\{ORG}/USD\{NAME}/USD\{VERSION}/USD\{VS_CODE_EXT1} USD\{URL_VS_CODE_EXT1} curl -sSL -o ./che-plugin-registry/v3/plugins/USD\{ORG}/USD\{NAME}/USD\{VERSION}/USD\{VS_CODE_EXT2} USD\{URL_VS_CODE_EXT2}
oc get checluster USD{CHECLUSTER_NAME} -o jsonpath='{.status.pluginRegistryURL}' -n USD{CODEREADY_NAMESPACE}
NEW_URL_VS_CODE_EXT1=http://USD\{PLUGIN_REG_URL}/v3/plugins/USD\{ORG}/USD\{NAME}/USD\{VERSION}/USD\{VS_CODE_EXT1} NEW_URL_VS_CODE_EXT2=http://USD\{PLUGIN_REG_URL}/v3/plugins/USD\{ORG}/USD\{NAME}/USD\{VERSION}/USD\{VS_CODE_EXT2} sed -i -e 's/USD\{URL_PLUGIN1}/USD\{NEW_URL_VS_CODE_EXT1}/g' ./che-plugin-registry/v3/plugins/USD\{ORG}/USD\{NAME}/USD\{VERSION}/meta.yaml sed -i -e 's/USD\{URL_PLUGIN2}/USD\{NEW_URL_VS_CODE_EXT2}/g' ./che-plugin-registry/v3/plugins/USD\{ORG}/USD\{NAME}/USD\{VERSION}/meta.yaml
git clone https://github.com/eclipse/che-plugin-registry; cd che-plugin-registry
PLUGIN="v3/plugins/new-org/new-plugin/0.0.1"; mkdir -p USD{PLUGIN}; cp v3/plugins/che-incubator/cpptools/0.1/* USD{PLUGIN}/ echo "USD{PLUGIN##*/}" > USD{PLUGIN}/../latest.txt
publisher: new-org name: new-plugin version: 0.0.1
PLUGIN_REG_POD=USD(oc get -o custom-columns=NAME:.metadata.name --no-headers pod -l component=plugin-registry)
cd che-plugin-registry; "USD(pwd)/build/scripts/generate_latest_metas.sh" v3 && "USD(pwd)/build/scripts/check_plugins_location.sh" v3 && "USD(pwd)/build/scripts/set_plugin_dates.sh" v3 && "USD(pwd)/build/scripts/check_plugins_viewer_mandatory_fields.sh" v3 && "USD(pwd)/build/scripts/index.sh" v3 > v3/plugins/index.json
cd che-plugin-registry; LOCAL_FILES="USD(pwd)/USD{PLUGIN}/meta.yaml USD(pwd)/v3/plugins/index.json"; oc exec USD{PLUGIN_REG_POD} -i -t -- mkdir -p /var/www/html/USD{PLUGIN}; for f in USDLOCAL_FILES; do e=USD{f/USD(pwd)\//}; echo "Upload USD{f} -> /var/www/html/USD{e}"; oc cp "USD{f}" USD{PLUGIN_REG_POD}:/var/www/html/USD{e}; done
git clone https://github.com/eclipse/che-devfile-registry; cd che-devfile-registry
STACK="new-stack"; mkdir -p devfiles/USD{STACK}; cp devfiles/nodejs/* devfiles/USD{STACK}/
DEVFILE_REG_POD=USD(oc get -o custom-columns=NAME:.metadata.name --no-headers pod -l component=devfile-registry)
cd che-devfile-registry; "USD(pwd)/build/scripts/check_mandatory_fields.sh" devfiles; "USD(pwd)/build/scripts/index.sh" > index.json
cd che-devfile-registry; LOCAL_FILES="USD(pwd)/USD{STACK}/meta.yaml USD(pwd)/USD{STACK}/devfile.yaml USD(pwd)/index.json"; oc exec USD{DEVFILE_REG_POD} -i -t -- mkdir -p /var/www/html/devfiles/USD{STACK}; for f in USDLOCAL_FILES; do e=USD{f/USD(pwd)\//}; echo "Upload USD{f} -> /var/www/html/devfiles/USD{e}" oc cp "USD{f}" USD{DEVFILE_REG_POD}:/var/www/html/devfiles/USD{e}; done