portainer/portainer

View on GitHub
api/http/handler/helm/handler.go

Summary

Maintainability
A
1 hr
Test Coverage
package helm

import (
    "net/http"

    portainer "github.com/portainer/portainer/api"
    "github.com/portainer/portainer/api/dataservices"
    "github.com/portainer/portainer/api/http/middlewares"
    "github.com/portainer/portainer/api/http/security"
    "github.com/portainer/portainer/api/kubernetes"
    "github.com/portainer/portainer/pkg/libhelm"
    "github.com/portainer/portainer/pkg/libhelm/options"
    httperror "github.com/portainer/portainer/pkg/libhttp/error"

    "github.com/gorilla/mux"
)

// Handler is the HTTP handler used to handle environment(endpoint) group operations.
type Handler struct {
    *mux.Router
    requestBouncer           security.BouncerService
    dataStore                dataservices.DataStore
    jwtService               portainer.JWTService
    kubeClusterAccessService kubernetes.KubeClusterAccessService
    kubernetesDeployer       portainer.KubernetesDeployer
    helmPackageManager       libhelm.HelmPackageManager
}

// NewHandler creates a handler to manage endpoint group operations.
func NewHandler(bouncer security.BouncerService, dataStore dataservices.DataStore, jwtService portainer.JWTService, kubernetesDeployer portainer.KubernetesDeployer, helmPackageManager libhelm.HelmPackageManager, kubeClusterAccessService kubernetes.KubeClusterAccessService) *Handler {
    h := &Handler{
        Router:                   mux.NewRouter(),
        requestBouncer:           bouncer,
        dataStore:                dataStore,
        jwtService:               jwtService,
        kubernetesDeployer:       kubernetesDeployer,
        helmPackageManager:       helmPackageManager,
        kubeClusterAccessService: kubeClusterAccessService,
    }

    h.Use(middlewares.WithEndpoint(dataStore.Endpoint(), "id"),
        bouncer.AuthenticatedAccess)

    // `helm list -o json`
    h.Handle("/{id}/kubernetes/helm",
        httperror.LoggerHandler(h.helmList)).Methods(http.MethodGet)

    // `helm delete RELEASE_NAME`
    h.Handle("/{id}/kubernetes/helm/{release}",
        httperror.LoggerHandler(h.helmDelete)).Methods(http.MethodDelete)

    // `helm install [NAME] [CHART] flags`
    h.Handle("/{id}/kubernetes/helm",
        httperror.LoggerHandler(h.helmInstall)).Methods(http.MethodPost)

    // Deprecated
    h.Handle("/{id}/kubernetes/helm/repositories",
        httperror.LoggerHandler(h.userGetHelmRepos)).Methods(http.MethodGet)
    h.Handle("/{id}/kubernetes/helm/repositories",
        httperror.LoggerHandler(h.userCreateHelmRepo)).Methods(http.MethodPost)

    return h
}

// NewTemplateHandler creates a template handler to manage environment(endpoint) group operations.
func NewTemplateHandler(bouncer security.BouncerService, helmPackageManager libhelm.HelmPackageManager) *Handler {
    h := &Handler{
        Router:             mux.NewRouter(),
        helmPackageManager: helmPackageManager,
        requestBouncer:     bouncer,
    }

    h.Use(bouncer.AuthenticatedAccess)

    h.Handle("/templates/helm",
        httperror.LoggerHandler(h.helmRepoSearch)).Methods(http.MethodGet)

    // helm show [COMMAND] [CHART] [REPO] flags
    h.Handle("/templates/helm/{command:chart|values|readme}",
        httperror.LoggerHandler(h.helmShow)).Methods(http.MethodGet)

    return h
}

// getHelmClusterAccess obtains the core k8s cluster access details from request.
// The cluster access includes the cluster server url, the user's bearer token and the tls certificate.
// The cluster access is passed in as kube config CLI params to helm binary.
func (handler *Handler) getHelmClusterAccess(r *http.Request) (*options.KubernetesClusterAccess, *httperror.HandlerError) {
    endpoint, err := middlewares.FetchEndpoint(r)
    if err != nil {
        return nil, httperror.NotFound("Unable to find an environment on request context", err)
    }

    tokenData, err := security.RetrieveTokenData(r)
    if err != nil {
        return nil, httperror.InternalServerError("Unable to retrieve user authentication token", err)
    }

    bearerToken, _, err := handler.jwtService.GenerateToken(tokenData)
    if err != nil {
        return nil, httperror.Unauthorized("Unauthorized", err)
    }

    sslSettings, err := handler.dataStore.SSLSettings().Settings()
    if err != nil {
        return nil, httperror.InternalServerError("Unable to retrieve settings from the database", err)
    }

    hostURL := "localhost"
    if !sslSettings.SelfSigned {
        hostURL = r.Host
    }

    kubeConfigInternal := handler.kubeClusterAccessService.GetClusterDetails(hostURL, endpoint.ID, true)
    return &options.KubernetesClusterAccess{
        ClusterServerURL:         kubeConfigInternal.ClusterServerURL,
        CertificateAuthorityFile: kubeConfigInternal.CertificateAuthorityFile,
        AuthToken:                bearerToken,
    }, nil
}