Documentation

Actions

Actions are scripts written in bash or python that are configured with a json file. These scripts can be used to automate your workflow - removing the need to memorize common commands. Actions are located on the filesystem at ~/Library/Application\ Support/Kubermagic/Actions, which can be opened in Kubermagic through the menu bar: Actions: Show in Finder.

A basic action is just a directory with either a main.bash/main.py file and config.json.

Picture of a simple action

Organization and Grouping

Actions can be organized using subdirectories in the filesystem. To group actions together, simply place the actions directories together in a parent directory. Action groups can be grouped together into further subgroups.

Picture of a nested action directory

Shell Actions

Shell actions are created by adding a main.* script to an action directory (main.sh, main.fish, or main.py for example). A shell script must have a shebang to point the script interpreter. Shell scripts are useful for saving commonly used kubectl commands. The output can be sent to the terminal, or can open up a new terminal session. Some examples are included to get in idea of the potential of shell actions.

Environment variables

Environment variables need to be declared within Kubermagic as scripts run in an independant shell environment and will not inherit environment variables like $PATH. Custom environment variables can be set for use within actions in Kubermagic: Preferences: Advanced. Actions must declare which environment variables will be needed with the environment_variables config file setting.

The script automatically recieves the following environment variables:

KUBECTL
The location of the application's built-in version of kubectl.

CONTEXT
The currently active context.

NAMESPACE
The currently selected namespace.

POD, CONTAINER, DEPLOYMENT, SERVICE, ENDPOINT, CRONJOB, JOB, PERSISTENTVOLUME, CONFIGMAP, SECRET, EVENT
Depending on the scope, the selected pod, deployment, etc.. is passed as an environment variable. (Both POD and CONTAINER will be set if setting scope is set to container)

Running shell commands

Shell scripts runs in their own shell environment, so will need explicit locations to binaries if using other shell commands.

Smart Actions

Basic Structure

Kubermagic includes Python 3.7 that allows for advanced, interactive scripting. For Kubermagic to recognize an action as a smart action, the setting is_smart_action must be set to true in config.json. A Kubermagic smart action has the following components:

from kubermagic import KubermagicAction  # 1

class Action(KubermagicAction): # 2
    def run(self):
        print("Hello, world!")

if __name__ == "__main__": # 3
    a = Action()
    a.test_run()
  1. A kubermagic library is available for scripts run from kubermagic.

  2. Each action must have a class titled Action that inherits from KubermagicAction. The run() method will be called on invocation.

  3. (Optional) To test the script locally without having to go through the app, a test_run() method is included. (Add /<path to app>/Kubermagic.app/Contents/Resources/python3.7/lib/site-packages to sys.path to test locally.)

Action Methods

There are a handful of API methods that allow for interacting with Kubermagic. Due to how the Kubermagic interacts with the python interpreter, the following methods suspend script execution while the dialog/panel waits for user input. The script resumes at the callback method passing in the user input as a parameter.

from kubermagic import KubermagicAction

class Action(KubermagicAction):
    def run(self):
        self.ok_cancel_dialog(
            title="Title",
            dialog_text="This is the OK/Cancel dialog text.",
            callback=self.ok_callback
        )

    def ok_callback(self, ok_clicked):
        if ok_clicked:
            print("OK Button Pressed")
        else:
            print("Cancel Button Pressed")

kubermagic.KubermagicAction methods

notification()

.notification(self, title, subtitle="", informative_text="", callback=None)
Display a notification center alert.

ok_dialog()

.ok_dialog(self, title, dialog_text, ok_button_text=None, callback=None)
Display a panel with a button.

ok_cancel_dialog()

.ok_cancel_dialog(self, title, dialog_text, ok_button_text="OK", cancel_button_text="Cancel", callback=None)
Display a panel with a two buttons.

form_dialog()

.form_dialog(self, title, dialog_text, form, ok_button_text="OK", cancel_button_text="Cancel", callback=None)
Display a panel with a form. (See below)

Forms

Forms are a powerful feature of Kubermagic that provides interactive actions. Let's jump into an example:

from kubermagic import KubermagicAction, forms  # 1

GREETING_CHOICES = (
    'Hello',
    'Goodbye',
)

class GreetingForm(forms.Form):  # 2
    name = forms.TextField(placeholder="Your name")
    greeting = forms.DropdownField(choices=GREETING_CHOICES)
    is_exclamation = forms.CheckboxField(label="Add Exclamation", checked=False)

class Action(KubermagicAction):

    def run(self):
        form = GreetingForm()  # 3
        self.form_dialog(
            "Greeting Form", "Please select how you would like to be greeted.",
            form, ok_button_text="Greet me", callback=self.greet_callback
        )

    def greet_callback(self, form_data):  # 4

        greeting = form_data["greeting"]
        name = form_data["name"]
        exclamation = form_data["is_exclamation"]

        output = f"{greeting}, {name} {'!!!' if exclamation else ''}"
        self.ok_dialog("Hello world result.", output, "Why, thank you!")
  1. If using forms, the Kubermagic forms module must be imported.
  2. A form class is created with fields that will display to the user.
  3. The form is instantiated and displayed in Kubermagic with form_dialog().
  4. The callback method runs with the user input passed as the first argument when the user presses the default button.

The resulting form will display in the app when run.

Screenshot of a sample action

Built-in Field classes

Common field attributes

label
The label argument lets you specify a "human-friendly" label for this field. The default label for a Field is generated from the field name by converting all underscores to spaces and upper-casing the first letter.

class TextField(label=None, initial="", placeholder="")

initial
The initial value

placeholder
Placeholder text if no text has been entered.

class DropdownField(label=None, choices=(), initial=None)

choices
A list or set of strings to use in the dropdown menu.

initial
The initial value

class CheckboxField(label=None, checked=False)

checked
If True (default False), the box will open with a checkmark.

Modifying forms after load

Forms can have their fields modified after load. For instance, one might want to load a list of tags from github for a dropdown field. This is done by creating a form field without the dynamic parameters. After the form is instantiated, one can populate those values by accessing the fields using form.fields.

class TestForm(forms.Form):
    tag = forms.DropdownField()

...

form = TestForm()
form.fields["tag"].choices = ("Tag 1", "Tag 2", "Tag 3")
form.fields["tag"].initial = "Tag 2"

Convenience Libraries

The following libraries are included with Kubermagic and are ready to use out-of-the-box.

requests
A clean, user-friendly API for handling web requests. SOCKS support is included. Docs

urllib3
Python HTTP library with thread-safe connection pooling, file post support, sanity friendly, and more. Docs

pyyaml
PyYAML is a YAML parser and emitter for Python. Docs

Sharing actions

Actions can be written for personal user or shared to assist colleagues or clients. To share actions, it is recommended to create Action Packs - a group of actions that is version controlled. These packs can be updated and shared throughout an organization.

The Config File

environment_variables [list of strings] default: []
Additional environment variables that will be passed to the script. These need to be set by the user in Kubermagic's preferences. The script will warn the user in the console if there is a missing variable.

open_in_terminal [bool] default: false
If true, action will open in a new terminal window instead of the Kubermagic console.

scope [str]
must be one of "namespace", "pod", "container". Action will only be enabled if selection of scope has been made.

show_warning_text [str]
On commands that might have irreversable effects on a system, this will display the specified warning message within an "OK/Cancel" dialog box.

use_name_matching_pattern [str]
When scope is set to pod, will automatically select the first pod matching the glob-style pattern. This helps prevent the need to manually select a pod from a list. If multiple pods match the pattern, the first pod in alphabetical order will be used. If multiple pods match, but one of these pods is selected in teh table, the selected pod will be used. If a pod is selected that does not match pattern, the selection is ignored and the first matching pod is used.

Only basic * wildcards are currently supported.

  • To match a pod containing "hello-minikube", use "*hello-minikube*".
  • To match a pod starting with "hello-minikube", use "hello-minikube*"

is_smart_action [bool] default: false
If true, and a main.py file exists in the action, the action will be treated as a Smart Action.

Config Example

{
    "open_in_terminal": false,
    "scope": "namespace",
    "environment_variables": ["GITHUB_TOKEN"],
    "use_name_matching_pattern": "*scheduler*",
    "is_smart_action": false
}

Icons

The action can be further dressed up by adding the following files to the action directory.

  • icon.png - a 64x64 image that will display as the toolbar icon

  • menu.png - a 32x32 image that will display in the menubar

Examples

Shell Examples

Hello, World

#!/bin/bash
echo "Hello, World!"

Run a postgres query

Find a pod with the word postgrespod in it, and return the currently running queries.

#!/bin/bash
echo "Fetching current processes"
$KUBECTL exec -it -n "$NAMESPACE" "$POD" -- psql host="$NAMESPACE-pgdb dbname=<dbname> user=<user> password=<password> sslmode=require" -c"select * from pg_stat_activity;" -P pager=off
{
    "use_name_matching_pattern": "*postgrespod*"
}

Open a shell

Open a new terminal window with the shell of a pod that contains apps

#!/bin/bash
$KUBECTL exec -it -n "$NAMESPACE" "$POD" -c containername sh
{
    "open_in_terminal": true,
    "use_name_matching_pattern": "*apps*"
}

Port Forward and Open in Browser

Initiate port-forwarding from a pod and open a new browser window to that port.

To link two or more related actions together, one can run commands in the background and use wait. (open_in_terminal must be set for this action to run correctly as this will keep the port-forward process alive.)

#!/bin/env bash
$KUBECTL port-forward -n "$NAMESPACE" "$POD" 1443:443 &
P1=$!
sleep 2; open -a "Google Chrome" https://127.0.0.1:1443 &
P2=$!
wait $P1 $P2

Python Examples

Hello, World in Python

A simple Kubermagic python action.

from kubermagic import KubermagicAction

class Action(KubermagicAction):

    def run(self):
        print("Hello, world from python.")

A simple form

A python form class is created by inheriting from kubermagic.forms.Form. Fields are declared as class properties. When the action is started, the run command is called and form displayed to the user. When the user completes the form, the data is passed back to the callback and a dialog is displayed to the user.

from kubermagic import KubermagicAction, forms


GREETING_CHOICES = (
    'Hello',
    'Goodbye',
)


class GreetingForm(forms.Form):
    name = forms.TextField(placeholder="Your name")
    greeting = forms.DropdownField(choices=GREETING_CHOICES)
    is_exclamation = forms.CheckboxField(label="Add Exclamation", checked=False)


class Action(KubermagicAction):

    def run(self):
        form = GreetingForm()
        self.form_dialog(
            "Greeting Form", "Please select how you would like to be greeted.",
            form, ok_button_text="Greet me", callback=self.greet_callback
        )

    def greet_callback(self, form_data):

        print("Data from form:", form_data)

        greeting = form_data["greeting"]
        name = form_data["name"]
        exclamation = form_data["is_exclamation"]

        output = f"{greeting}, {name} {'!!!' if exclamation else ''}"
        self.ok_dialog("Hello world result.", output, "Why, thank you!")

Contents