DEV Community

Cover image for Making UI for Helm in ~100 lines of code
DevOps Pass AI for DevOps Pass AI

Posted on

Making UI for Helm in ~100 lines of code

Hey folks, pretty often I can hear from colleagues "We're using custom solution/API/tool for ..." Which usually means someone create some tool, but usually forgot to add any convenient interface except shell :D

Let's try on example of Helm use DevOps Pass plugins feature and create UI for it.
In the same way you can create UI for any API/CLI tool you have in your stack.

📝 Requirements

What we want to achieve:

  • List installed Helm releases in current Kubernetes context
  • List and manage Helm repos
  • List and install Helm chart from list

Ok, so we need three doc's to list entities and few more actions for that docs.

Lets go!

⛑️ Add Helm App

First of all let's add Helm into the list of DOP applications.

Go to "DevOps Pass AI" application (add if not added from apps list) and click "Add App" action.

Fill necessary fields. Dont forget about github repo name - helm/helm - https://github.com/helm/helm, this field will help to generate "Install Helm" action

Helm app

Click create and reload plugins (click on your avatar at the right top). After that you will be able to add it from applications list.

📦 Helm repos

Now lets create doc types for Helm releases, Helm repos and Helm charts, use "Add document type" action from DOP app:

Doc type create

It will generate for you Python files list this:

import subprocess
import json
import yaml
import requests
import cdx

def error(msg: str):
    return [
            {
                'name': 'ERROR',
                'icon': 'assets/icons/general/error.png',
                'error': '```

' + msg + '

```'
            }
        ]

def list():
    # Run the command and capture the output
    #
    # output = subprocess.run(['docker', 'compose', 'ls', '--format', 'json'], text=True, check=True, capture_output=True)
    # # Parse the output to extract environment information
    # repos = json.loads(output.stdout)

    # Kick API and return result
    #
    # url = f'https://some.url.com/'
    # token = cdx.settings.get('github.token')
    # headers = {
    #     'Authorization': f"Bearer {token}",
    # }
    # resp = requests.get(url, headers=headers)
    # if resp.status_code == 200:
    #     return resp.json()
    # else:
    #     return error(f"Something went wrong: {resp.content}")

    return error("Not implemented!")
Enter fullscreen mode Exit fullscreen mode

There is an example for HTTP API call or shell command run.

First of all Helm has wonderful feature - output in JSON format, so we can use it to receive currently installed repos, releases and existing charts.

Repos, simple-stupid, just return as-is:

import json
import subprocess
import re
import cdx

def list():
    try:
        # Run the command and capture the output
        output = subprocess.run(['helm', 'repo', 'list', '-o', 'json'], text=True, check=True, capture_output=True)
        return json.loads(output.stdout)

    except subprocess.CalledProcessError as e:
        return [{'name': 'ERROR', 'icon': 'assets/icons/general/error.png', 'error': f"{e}\n{e.output}\n{e.stderr}"}]
    except FileNotFoundError as e:
        return [
            {
                'name': 'ERROR',
                'icon': 'assets/icons/general/error.png',
                'error': f"Can't find 'helm' in PATH, looks like its not installed, please install first"
            }
        ]
Enter fullscreen mode Exit fullscreen mode

Helm releases. Icon mappings used to make output a bit prettier and if helm name is one of predefined - add icon for it.

import subprocess
import json
import cdx

def get_icon(chart_name):
    icon_mapping = {
        "gitea": "apps/gitea.png",
        ....
    }

    # Extract the base image name from the full image name
    chart_name = chart_name.split("/")[-1]

    matching_keys = [key for key in icon_mapping.keys() if key in chart_name]

    # Use the mapping, or default to "unknown.png" if not found
    return icon_mapping.get(matching_keys[0], None) if matching_keys else 'apps/helm.png'

def list():
    try:
        # Run the command and capture the output
        output = subprocess.run(['helm', 'list', '-o', 'json'], text=True, capture_output=True, check=True)
        ret = []
        # Parse the output to extract environment information
        releases = json.loads(output.stdout)
        for release in releases:
            release['icon'] = 'assets/icons/' + get_icon(release['name'])
            ret.append(release)

        return releases

    except subprocess.CalledProcessError as e:
        return [{'name': 'ERROR', 'icon': 'assets/icons/general/error.png', 'error': f"{e}\n{e.output}\n{e.stderr}"}]
    except FileNotFoundError as e:
        return [
            {
                'name': 'ERROR',
                'icon': 'assets/icons/general/error.png',
                'error': f"Can't find 'helm' in PATH, looks like its not installed, please install first"
            }
        ]
Enter fullscreen mode Exit fullscreen mode

Lets list available Helm charts:

import subprocess
import json
import cdx

def get_icon(chart_name):
    icon_mapping = {
        "gitea": "apps/gitea.png", 
        # ...
    }

    # Extract the base image name from the full image name
    chart_name = chart_name.split("/")[-1]

    matching_keys = [key for key in icon_mapping.keys() if key in chart_name]

    # Use the mapping, or default to "unknown.png" if not found
    return icon_mapping.get(matching_keys[0], None) if matching_keys else 'apps/helm.png'

def list():
    try:
        # Run the command and capture the output
        output = subprocess.run(['helm', 'search', 'repo', '-o', 'json'], text=True, check=True, capture_output=True)
        ret = []
        # Parse the output to extract environment information
        repos = json.loads(output.stdout)
        for repo in repos:
            repo['icon'] = 'assets/icons/' + get_icon(repo['name'])
            ret.append(repo)

        return repos

    except subprocess.CalledProcessError as e:
        return [{'name': 'ERROR', 'icon': 'assets/icons/general/error.png', 'error': f"{e}\n{e.output}\n{e.stderr}"}]
    except FileNotFoundError as e:
        return [
            {
                'name': 'ERROR',
                'icon': 'assets/icons/general/error.png',
                'error': f"Can't find 'helm' in PATH, looks like its not installed, please install first"
            }
        ]
Enter fullscreen mode Exit fullscreen mode

Lets create application action for repo adding:

App action

🏆 Result

As a result we getting UI where you can see Helm releases installed in current context, Helm repos and Helm charts available in that repos:

Helm Charts

Next actions - add install, release test actions for charts/releases and that's it - https://github.com/devopspass/plugins/tree/main/helm

helm_repo

  • Refresh info
  • Remove repo

helm_repo_chart

  • Install Chart
  • Open Chart Source

helm_release

  • Test Release
  • Remove Release

With just a few hundred of code lines you've created UI for Helm, when some companies even trying to sell solutions like that...

You can do the same for any API/CLI you're using daily.

🌟 Support Us, Contact Us

Give us a start, we’re kitties ;)

If you like this post, support us, download, try and give us feedback!

Give us a star 🌟 on GitHub or join our community on Slack.

Top comments (4)

Collapse
 
dexterous7202 profile image
Dexterous7202 • Edited

Thanks for the post! What platform is this that you're running this in? i.e. what GUI app are you in when you say

"First of all let's add Helm into the list of DOP applications. Go to "DevOps Pass AI" application (add if not added from apps list) and click "Add App" action."

and when you show the first screenshot with the icons of DevOps tools on the right side vertical panel?

Collapse
 
devopspass profile image
DevOps Pass AI

Last section has link to GitHub repo - github.com/devopspass/devopspass/

All apps on the left added as plugins, DevOps Pass only provides functionality, all the rest is addon :)

Collapse
 
dexterous7202 profile image
Dexterous7202

OK, I see, so it's the Devops Pass AI plugin in Devops Pass itself...that was what confused me. Thanks

Thread Thread
 
devopspass profile image
DevOps Pass AI

Yep, plugins used to simplify development of new plugins :)
Have you tried app already?