Link Search Menu Expand Document

Generating custom Helm charts to illustrate adding custom files and directories in custom locations

Big picture

Move2Kube allows custom templated files to be added to directories of choice. In this example, we illustrate it by adding a custom helm-chart.

  1. Let us start by creating an empty workspace directory say workspace and make it the current working directory. We will assume all commands are executed within this directory.
     $ mkdir workspace && cd workspace
    
  2. Lets use the enterprise-app as input for this flow.
     $ curl https://move2kube.konveyor.io/scripts/download.sh | bash -s -- -d samples/enterprise-app/src -r move2kube-demos  
     $ ls src
     README.md		config-utils		customers	docs			frontend		gateway			orders
    

    In this project, all the apps have a pom.xml file. Lets use a custom transformer to put a helm chart created out of a template into each of those project directories.

  3. We will use the starlark based custom transformer in here. We copy it into the customizations sub-directory.
     $ curl https://move2kube.konveyor.io/scripts/download.sh | bash -s -- -d add-custom-files-directories-in-custom-locations -r move2kube-transformers -o customizations
    
  4. Now lets transform with this customization. Specify the customization using the -c flag.
     $ move2kube transform -s src/ -c customizations/ --qa-skip
    

Once the output is generated, we can observe one helm-chart is generated for each service and placed within the service directory. Also, note that every helm-chart project is named after the service it is meant for. The contents are shown below for reference: ```

    $ tree myproject
        myproject/
        ├── config-utils
        │   ├── helm-chart
        │   │   └── config-utils
        │   │       ├── Chart.yaml
        │   │       ├── templates
        │   │       │   ├── config-utils-deployment.yaml
        │   │       │   ├── config-utils-ingress.yaml
        │   │       │   └── config-utils-service.yaml
        │   │       └── values.yaml
        │   ├── pom.xml
        │   └── src
        │       └── main
        │           └── java
        │               └── io
        │                   └── konveyor
        │                       └── demo
        │                           └── config
        │                               └── ApplicationConfiguration.java
        ├── customers
        │   ├── Makefile
        │   ├── helm-chart
        │   │   └── customers
        │   │       ├── Chart.yaml
        │   │       ├── templates
        │   │       │   ├── customers-deployment.yaml
        │   │       │   ├── customers-ingress.yaml
        │   │       │   └── customers-service.yaml
        │   │       └── values.yaml
        │   ├── pom.xml
        │   └── src
        │       └── main
        │           ├── java
        │           │   └── io
        │           │       └── konveyor
        │           │           └── demo
        │           │               └── ordermanagement
        │           │                   ├── OrderManagementAppInitializer.java
        │           │                   ├── config
        │           │                   │   ├── PersistenceConfig.java
        │           │                   │   └── WebConfig.java
        │           │                   ├── controller
        │           │                   │   └── CustomerController.java
        │           │                   ├── exception
        │           │                   │   ├── ResourceNotFoundException.java
        │           │                   │   └── handler
        │           │                   │       └── ExceptionHandlingController.java
        │           │                   ├── model
        │           │                   │   └── Customer.java
        │           │                   ├── repository
        │           │                   │   └── CustomerRepository.java
        │           │                   └── service
        │           │                       └── CustomerService.java
        │           └── resources
        │               ├── import.sql
        │               └── persistence.properties
        └── gateway
            ├── helm-chart
            │   └── snowdrop-dependencies
            │       ├── Chart.yaml
            │       ├── templates
            │       │   ├── snowdrop-dependencies-deployment.yaml
            │       │   ├── snowdrop-dependencies-ingress.yaml
            │       │   └── snowdrop-dependencies-service.yaml
            │       └── values.yaml
            ├── manifest.yml
            ├── pom.xml
            └── src
                ├── main
                │   ├── java
                │   │   ├── META-INF
                │   │   │   └── MANIFEST.MF
                │   │   └── io
                │   │       └── konveyor
                │   │           └── demo
                │   │               └── gateway
                │   │                   ├── Application.java
                │   │                   ├── command
                │   │                   │   └── ProductCommand.java
                │   │                   ├── controller
                │   │                   │   ├── CustomersController.java
                │   │                   │   ├── InventoryController.java
                │   │                   │   └── OrdersController.java
                │   │                   ├── exception
                │   │                   │   ├── ResourceNotFoundException.java
                │   │                   │   └── handler
                │   │                   │       └── ExceptionHandlingController.java
                │   │                   ├── model
                │   │                   │   ├── Customer.java
                │   │                   │   ├── Order.java
                │   │                   │   ├── OrderItem.java
                │   │                   │   ├── OrderSummary.java
                │   │                   │   └── Product.java
                │   │                   ├── repository
                │   │                   │   ├── CustomerRepository.java
                │   │                   │   ├── GenericRepository.java
                │   │                   │   ├── InventoryRepository.java
                │   │                   │   └── OrderRepository.java
                │   │                   ├── serialization
                │   │                   │   ├── CustomerDeserializer.java
                │   │                   │   └── ProductDeserializer.java
                │   │                   └── service
                │   │                       ├── CustomersService.java
                │   │                       ├── InventoryService.java
                │   │                       └── OrdersService.java
                │   └── resources
                │       ├── application-local.properties
                │       ├── application-openshift.properties
                │       └── bootstrap.properties
                └── test
                    ├── java
                    │   └── io
                    │       └── konveyor
                    │           └── demo
                    │               └── gateway
                    │                   ├── controller
                    │                   │   └── OrdersControllerTest.java
                    │                   ├── model
                    │                   │   └── OrderTest.java
                    │                   ├── repository
                    │                   │   ├── CustomerRepositoryTest.java
                    │                   │   ├── InventoryRepositoryTest.java
                    │                   │   └── OrderRepositoryTest.java
                    │                   └── service
                    │                       └── OrdersServiceTest.java
                    └── resources
                        ├── application-test.properties
                        └── bootstrap.properties

```

Anatomy of transformer in add-custom-files-directories-in-custom-locations

This custom transformer is more advanced compared to the previous cases as it uses a starlark script (customhelmchartgen.star) and several templatization features (notice the {{\ .ServiceName\ }} template in the file names of custom helm-chart template in the templates sub-directory) to achieve the per-service helm-chart requirement. The contents of add-custom-files-directories-in-custom-locations custom transformer are as shown below:

customization/add-custom-files-directories-in-custom-locations/
├── customhelmchartgen.star
├── customhelmchartgen.yaml
└── templates
    └── helm-chart
        └── {{\ .ServiceName\ }}
            ├── Chart.yaml
            ├── templates
            │   ├── {{\ .ServiceName\ }}-deployment.yaml
            │   ├── {{\ .ServiceName\ }}-ingress.yaml
            │   └── {{\ .ServiceName\ }}-service.yaml
            └── values.yaml

The code of the starlark script (cat customizations/add-custom-files-directories-in-custom-locations/customhelmchartgen.star) is shown below. At a high level, the custom transformer detects (in the detect phase where directory_detect() function is invoked) a Java project if it finds pom.xml in the directory. Once the Java project is detected, the corresponding project path and service name are passed to the transform phase through Move2Kube. In the transform phase, the transform() function is invoked with the discovered service artifacts (from detect phase). These artifacts are used to fill the helm-chart templates shown above and produced as the output in a per-service directory structure.

PomFile = "pom.xml"

# Performs the detection of pom file and extracts service name
def directory_detect(dir):
    dataFilePath = fs.pathjoin(dir, PomFile)
    if fs.exists(dataFilePath):
        serviceName = getServiceName(dataFilePath)
        return  {serviceName: [{
                    "paths": {"ProjectPath": [dir]} }] }

# Creates the customized helm chart for every service
def transform(new_artifacts, old_artifacts):
    pathMappings = []
    artifacts = []
    pathTemplate = "{{ SourceRel .ServiceFsPath }}"
    for v in new_artifacts:
        serviceName = v["configs"]["Service"]["serviceName"]
        dir = v['paths']['ProjectPath'][0]
        # Create a path template for the service
        pathTemplateName = serviceName.replace("-", "") + 'path'
        tplPathData = {'ServiceFsPath': dir, 'PathTemplateName': pathTemplateName}
        pathMappings.append({'type': 'PathTemplate', \
                            'sourcePath': pathTemplate, \
                            'templateConfig': tplPathData})
        # Since the helm chart uses the same templating character {{ }} as Golang templates, 
        # we use `SpecialTemplate` type here where the templating character is <~ ~>.
        # The `Template` type can be used for all normal cases
        pathMappings.append({'type': 'SpecialTemplate', \
                    'destinationPath': "{{ ." + pathTemplateName + " }}", \
                    'templateConfig': {'ServiceFsPath': dir, 'ServiceName': serviceName}})
        pathMappings.append({'type': 'Source', \
                    'sourcePath': "{{ ." + pathTemplateName + " }}",
                    'destinationPath': "{{ ." + pathTemplateName + " }}"})

    return {'pathMappings': pathMappings, 'artifacts': artifacts}

# Extracts service name from pom file
def getServiceName(filePath):
    data = fs.read(filePath)
    lines = data.splitlines()
    for l in lines:
        if 'artifactId' in l:
            t = l.split('>')
            t2 = t[1].split('<')
            return t2[0]