-
Notifications
You must be signed in to change notification settings - Fork 53
Creator: HOWTO Create a Language Generator
As we already read in the page about Runtime Generators, HOWTO Create a Runtime Generator, they are meant as a basis for other Generators to build on. They provide all the necessary files (code, configuration, build etc) to create a project for a certain framework. But that's all about the code and files, and as you can imagine there are lots of different ways to write code and lots of different frameworks to choose from. You could write Runtime Generators for Vert.x, Wildfly, Spring Boot, etc, all very different, but they still have one thing in common: they all run on the JVM platform. That's where Language Generators come in.
A Language Generator is the thing that takes care of taking the code in your project and getting it compiled and running on Kubernetes or OpenShift.
⚠️ Kubernetes is mentioned here, but right now only OpenShift support has been implemented. Support for Kubernetes is currently in development.
So let's go through the steps of what it takes to create a Language Generator (this is starting to look very familiar, right?):
- Setup - Make sure your are set up by following the Quick Setup for Devs guide
-
Choose a name - First we need to choose a name for our new Language Generator. Language Generators generally start with the text
language-
, so let's go with the very originallanguage-example
. - Create a folder - And like before all the Language Generator's files need to live in a folder with the name of the Generator
$ mkdir creator/src/main/resources/META-INF/catalog/language-example
- Files - Language Generators don't generally need many files, but they follow the same pattern as all Generators:
language-example/
files/
gap
The important file here is a shell script called gap
. It's a script that's used to build and deploy code. The easiest thing to do is to just copy the gap
script from one of the existing Language Generators and adapt it to your specific language/platform. It's normally a simple 2-line change.
Show code
gap
#!/usr/bin/env bash
APP_NAME={{.application}}
SERVICE_NAME={{.serviceName}}
SCRIPT_DIR=$(cd "$(dirname "$BASH_SOURCE")" ; pwd -P)
OPENSHIFTIO_DIR=${SCRIPT_DIR}/.openshiftio
SOURCE_DIR=${SCRIPT_DIR}
if [[ ! -z "{{.subFolderName}}" ]]; then
SOURCE_DIR=${SOURCE_DIR}/..
SUB_DIR=/{{.subFolderName}}
fi
function do_deploy() {
PARAMS=""
REPO_URL=$(git config --get remote.origin.url || echo "")
if [[ ! -z "${REPO_URL}" ]]; then
PARAMS="$PARAMS -p=SOURCE_REPOSITORY_URL=${REPO_URL}"
fi
if [[ ! -z "${OPENSHIFT_CONSOLE_URL}" ]]; then
PARAMS="$PARAMS -p=OPENSHIFT_CONSOLE_URL=${OPENSHIFT_CONSOLE_URL}"
fi
if [[ -f ${OPENSHIFTIO_DIR}/application.yaml ]]; then
oc process -f ${OPENSHIFTIO_DIR}/application.yaml --ignore-unknown-parameters ${PARAMS} | oc apply -f -
fi
if [[ -f ${OPENSHIFTIO_DIR}/service.welcome.yaml ]]; then
oc process -f ${OPENSHIFTIO_DIR}/service.welcome.yaml --ignore-unknown-parameters ${PARAMS} | oc apply -f -
fi
}
function do_build() {
mvn package
}
function do_clean() {
mvn clean
}
function do_push() {
if [[ "$1" == "--source" || "$1" == "-s" || "$1" == "--binary" || "$1" == "-b" ]]; then
shift
oc start-build ${SERVICE_NAME} --from-dir ${SOURCE_DIR} "$@"
elif [[ "$1" == "--git" || "$1" == "-g" ]]; then
shift
oc start-build ${SERVICE_NAME} "$@"
else
oc start-build ${SERVICE_NAME} --from-dir ${SOURCE_DIR} "$@"
fi
}
function do_delete() {
oc delete all,secrets -l app=${APP_NAME}
}
while [[ $# > 0 ]]; do
CMD=$1
shift
ARGS=()
while [[ "$1" == -* ]]; do ARGS+=($1); shift; done
case "$CMD" in
"deploy")
do_deploy $ARGS
;;
"build")
do_build $ARGS
;;
"clean")
do_clean $ARGS
;;
"push")
do_push $ARGS
;;
"delete")
do_delete $ARGS
;;
esac
RES=$?
if [[ $RES > 0 ]]; then
exit $RES
fi
done
-
Create metadata - Our Generator also needs an
info.yaml
in the root of our folder that contains some important metadata. For our example we will use the following:
type: generator
config:
image: "registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift"
For Language Generators the most important information is the builder image specified by the image
property. It's the name of a special Docker image, a so-called S2I builder image, that was created specifically to compile and run the code for your language / platform. In this case we chose a RedHat provided S2I builder image for the Java platform.
⚠️ Language Generators need an S2I Builder Image to do their work. Creating an S2I Builder Image does not fall within the scope of this documentation. See the S2I GitHub repository and the OpenShift S2I Documentation for more information.
-
Register the image - We now need to register this image in the list of images. Just add a item to the end of the list with the exact same name we used in the
image
property. It would look something like this:
- id: nodeshift/centos7-s2i-nodejs
name: Generic Node.js Code Builder
metadata:
language: nodejs
isBuilder: true
suggestedEnv:
PORT: '8080'
- id: nodeshift/centos7-s2i-web-app
name: Web App Node.js Code Builder
metadata:
language: nodejs
isBuilder: true
- id: registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift
name: Java Code Builder
metadata:
language: java
isBuilder: true
Now you'll need to run ./creator/creator generate
from the root of the Launcher project. This will generate a Yaml file which needs to be added to the project as well.
- Register the Generator - Finally we need to register our Generator in the GeneratorInfo list just as explained in the basic HOWTO Create a Generator.
And that's it! As you can see Language Generators are basically still Generators, but they do need a bit more work and knowledge to make work. Good thing we made them reusable!
Now Generators aren't really meant to be used directly, they are the building blocks for Capabilities after all, but if you'd always have to set up a Capability just to test your work that would be a nuisance.
So to try out the effect of a single Generator you can run the following command:
$ creator apply --project testproject --name test component --generator=example-language
If everything works as it's supposed to, which it never does of course the first time, but when it does the output should look somewhat like this:
$ creator apply --project testproject --name test component --generator=example-language
Applied capability to 'testproject'
Go into that folder and type './gap deploy' while logged into OpenShift to create the application
in the currently active project. Afterwards type './gap push' at any time to push the current
application code to the project.
⚠️ The output is a bit optimistic in this case because Language generators are so very low on the Generator Food Chain that trying to run thegap
command as it suggests will likely only result in errors. That's okay, you can still take a look at the project that was generated to see if the Generator was working okay
Congratulations! You just wrote your first Language Generator and created a project with it!