Skip to content

feat: implement helm status command #349

@manusa

Description

@manusa

Description

The helm status command is currently not implemented in helm-java. This command is essential for monitoring and troubleshooting Helm deployments as it displays the current state and comprehensive information about a named release.

Background

The helm status command shows:

  • Last deployment time
  • Kubernetes namespace where the release exists
  • Current state (unknown, deployed, uninstalled, superseded, failed, uninstalling, pending-install, pending-upgrade, or pending-rollback)
  • Revision number
  • Description (completion or error message)
  • List of Kubernetes resources in the release
  • Test suite results (if applicable)
  • Additional notes provided by the chart

This is one of the most commonly used Helm commands for operations and troubleshooting. See the official documentation.

Related Commands

This is related to issue #97 which mentions missing commands. However, helm status was not explicitly listed there.

Proposed API

Following the existing patterns in the codebase (similar to ListCommand, GetCommand), the implementation should provide a fluent API:

// Basic usage
Release status = Helm.status("my-release")
    .withKubeConfig(kubeConfigPath)
    .call();

// With namespace
Release status = Helm.status("my-release")
    .withNamespace("my-namespace")
    .withKubeConfig(kubeConfigPath)
    .call();

// With specific revision
Release status = Helm.status("my-release")
    .withRevision(3)
    .withKubeConfig(kubeConfigPath)
    .call();

// Using kubeconfig contents
Release status = Helm.status("my-release")
    .withKubeConfigContents(kubeConfigYaml)
    .call();

Implementation Guide

1. Create Go Options struct and function (native/internal/helm/status.go)

package helm

import (
    "helm.sh/helm/v3/pkg/action"
)

type StatusOptions struct {
    ReleaseName        string
    Revision           int
    Namespace          string
    KubeConfig         string
    KubeConfigContents string
}

func Status(options *StatusOptions) (string, error) {
    cfg, err := NewCfg(&CfgOptions{
        KubeConfig:         options.KubeConfig,
        KubeConfigContents: options.KubeConfigContents,
        Namespace:          options.Namespace,
    })
    if err != nil {
        return "", err
    }
    
    client := action.NewStatus(cfg)
    if options.Revision > 0 {
        client.Version = options.Revision
    }
    
    rel, err := client.Run(options.ReleaseName)
    if err != nil {
        return "", err
    }
    
    // Use existing StatusReport function from helm.go
    return StatusReport(rel, true, false), nil
}

2. Add CGO export in native/main.go

Add the C struct definition (around line 199, following existing patterns):

struct StatusOptions {
    char* releaseName;
    int revision;
    char* namespace;
    char* kubeConfig;
    char* kubeConfigContents;
};

Add the export function (following the pattern of GetValues):

//export Status
func Status(options *C.struct_StatusOptions) C.Result {
    return result(helm.Status(&helm.StatusOptions{
        ReleaseName:        C.GoString(options.releaseName),
        Revision:           int(options.revision),
        Namespace:          C.GoString(options.namespace),
        KubeConfig:         C.GoString(options.kubeConfig),
        KubeConfigContents: C.GoString(options.kubeConfigContents),
    }))
}

3. Create JNA Options class (lib/api/src/main/java/com/marcnuri/helm/jni/StatusOptions.java)

package com.marcnuri.helm.jni;

import com.sun.jna.Structure;

@Structure.FieldOrder({
  "releaseName",
  "revision",
  "namespace",
  "kubeConfig",
  "kubeConfigContents"
})
public class StatusOptions extends Structure {
  public String releaseName;
  public int revision;
  public String namespace;
  public String kubeConfig;
  public String kubeConfigContents;

  public StatusOptions(String releaseName, int revision, String namespace, 
                       String kubeConfig, String kubeConfigContents) {
    this.releaseName = releaseName;
    this.revision = revision;
    this.namespace = namespace;
    this.kubeConfig = kubeConfig;
    this.kubeConfigContents = kubeConfigContents;
  }
}

4. Add method to HelmLib interface (lib/api/src/main/java/com/marcnuri/helm/jni/HelmLib.java)

Result Status(StatusOptions options);

5. Create StatusCommand class (helm-java/src/main/java/com/marcnuri/helm/StatusCommand.java)

Following the pattern of ListCommand and GetCommand.GetValuesSubcommand:

package com.marcnuri.helm;

import com.marcnuri.helm.jni.HelmLib;
import com.marcnuri.helm.jni.StatusOptions;
import java.nio.file.Path;

public class StatusCommand extends HelmCommand<Release> {

  private final String releaseName;
  private int revision;
  private String namespace;
  private Path kubeConfig;
  private String kubeConfigContents;

  public StatusCommand(HelmLib helmLib, String releaseName) {
    super(helmLib);
    this.releaseName = releaseName;
  }

  @Override
  public Release call() {
    return Release.parseSingle(run(hl -> hl.Status(new StatusOptions(
      releaseName,
      revision,
      namespace,
      toString(kubeConfig),
      kubeConfigContents
    ))));
  }

  public StatusCommand withRevision(int revision) {
    this.revision = revision;
    return this;
  }

  public StatusCommand withNamespace(String namespace) {
    this.namespace = namespace;
    return this;
  }

  public StatusCommand withKubeConfig(Path kubeConfig) {
    this.kubeConfig = kubeConfig;
    return this;
  }

  public StatusCommand withKubeConfigContents(String kubeConfigContents) {
    this.kubeConfigContents = kubeConfigContents;
    return this;
  }
}

6. Add factory method in Helm.java

/**
 * Display the status of the named release.
 *
 * @param releaseName name of the release.
 * @return a new {@link StatusCommand} instance.
 */
public static StatusCommand status(String releaseName) {
  return new StatusCommand(HelmLibHolder.INSTANCE.helmLib(), releaseName);
}

7. Add tests (helm-java/src/test/java/com/marcnuri/helm/HelmStatusTest.java)

Following the nested test pattern used in the project.

Acceptance Criteria

  • Create StatusOptions Go struct in native/internal/helm/status.go
  • Implement Status function in Go using action.NewStatus
  • Add CGO export Status in native/main.go
  • Create StatusOptions.java JNA structure in lib/api
  • Add Status method to HelmLib interface
  • Create StatusCommand.java in helm-java module
  • Add status(String releaseName) factory method to Helm.java
  • Existing Release class can be reused (already contains all needed fields)
  • Add unit tests for the new command
  • Add integration tests using Testcontainers/KinD
  • Update documentation if applicable

Tests

Following the project's testing philosophy (black-box, no mocks, nested structure):

  • HelmStatusTest
    • Valid
      • withName - Get status of an existing release
      • withNamespace - Get status with explicit namespace
      • withRevision - Get status of specific revision
      • withKubeConfigContents - Use inline kubeconfig
    • Invalid
      • nonExistentRelease - Should throw appropriate exception
      • invalidRevision - Should handle non-existent revision

Additional Information

  • CLI Reference: https://helm.sh/docs/helm/helm_status/
  • Helm SDK: Uses action.NewStatus from helm.sh/helm/v3/pkg/action
  • Priority: High - This is an essential command for release monitoring and troubleshooting
  • Complexity: Low-Medium - Similar pattern to existing GetValuesSubcommand

Notes

The existing Release class already contains the fields returned by status:

  • name, namespace, status, revision, lastDeployed, chart, appVersion, output

The StatusReport function in native/internal/helm/helm.go (line 96) already formats the release information and can be reused.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions