Making UI for Helm in ~100 lines of code
DevOps Pass AI
Posted on July 30, 2024
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
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:
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!")
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"
}
]
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"
}
]
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"
}
]
Lets create application action for repo adding:
π 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:
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
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.
Posted on July 30, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.