mirror of
https://github.com/portainer/portainer.git
synced 2025-08-02 20:35:25 +02:00
feat(helm): update helm view [r8s-256] (#582)
Co-authored-by: Cara Ryan <cara.ryan@portainer.io> Co-authored-by: James Player <james.player@portainer.io> Co-authored-by: stevensbkang <skan070@gmail.com>
This commit is contained in:
parent
46eddbe7b9
commit
0ca9321db1
57 changed files with 2635 additions and 222 deletions
63
pkg/libkubectl/client.go
Normal file
63
pkg/libkubectl/client.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package libkubectl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"k8s.io/cli-runtime/pkg/genericclioptions"
|
||||
"k8s.io/cli-runtime/pkg/genericiooptions"
|
||||
"k8s.io/kubectl/pkg/cmd/util"
|
||||
)
|
||||
|
||||
type ClientAccess struct {
|
||||
Token string
|
||||
ServerUrl string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
factory util.Factory
|
||||
streams genericclioptions.IOStreams
|
||||
out *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewClient creates a new kubectl client
|
||||
func NewClient(libKubectlAccess *ClientAccess, namespace, kubeconfig string, insecure bool) (*Client, error) {
|
||||
configFlags, err := generateConfigFlags(libKubectlAccess.Token, libKubectlAccess.ServerUrl, namespace, kubeconfig, insecure)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
streams, _, out, _ := genericiooptions.NewTestIOStreams()
|
||||
|
||||
return &Client{
|
||||
factory: util.NewFactory(configFlags),
|
||||
streams: streams,
|
||||
out: out,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// generateConfigFlags generates the config flags for the kubectl client
|
||||
// If kubeconfigPath is provided, it will be used instead of server and token
|
||||
// If server and token are provided, they will be used to connect to the cluster
|
||||
// If neither kubeconfigPath or server and token are provided, an error will be returned
|
||||
func generateConfigFlags(token, server, namespace, kubeconfigPath string, insecure bool) (*genericclioptions.ConfigFlags, error) {
|
||||
if kubeconfigPath == "" && (server == "" || token == "") {
|
||||
return nil, errors.New("must provide either a kubeconfig path or a server and token")
|
||||
}
|
||||
|
||||
configFlags := genericclioptions.NewConfigFlags(true)
|
||||
if namespace != "" {
|
||||
configFlags.Namespace = &namespace
|
||||
}
|
||||
|
||||
if kubeconfigPath != "" {
|
||||
configFlags.KubeConfig = &kubeconfigPath
|
||||
} else {
|
||||
configFlags.APIServer = &server
|
||||
configFlags.BearerToken = &token
|
||||
}
|
||||
|
||||
configFlags.Insecure = &insecure
|
||||
|
||||
return configFlags, nil
|
||||
}
|
101
pkg/libkubectl/client_test.go
Normal file
101
pkg/libkubectl/client_test.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
package libkubectl
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
libKubectlAccess ClientAccess
|
||||
namespace string
|
||||
kubeconfig string
|
||||
insecure bool
|
||||
wantErr bool
|
||||
errContains string
|
||||
}{
|
||||
{
|
||||
name: "valid client with token and server",
|
||||
libKubectlAccess: ClientAccess{Token: "test-token", ServerUrl: "https://localhost:6443"},
|
||||
namespace: "default",
|
||||
insecure: true,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "valid client with kubeconfig",
|
||||
kubeconfig: "/path/to/kubeconfig",
|
||||
namespace: "test-namespace",
|
||||
insecure: false,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "missing both token/server and kubeconfig",
|
||||
namespace: "default",
|
||||
insecure: false,
|
||||
wantErr: true,
|
||||
errContains: "must provide either a kubeconfig path or a server and token",
|
||||
},
|
||||
{
|
||||
name: "missing token with server",
|
||||
libKubectlAccess: ClientAccess{ServerUrl: "https://localhost:6443"},
|
||||
namespace: "default",
|
||||
insecure: false,
|
||||
wantErr: true,
|
||||
errContains: "must provide either a kubeconfig path or a server and token",
|
||||
},
|
||||
{
|
||||
name: "missing server with token",
|
||||
libKubectlAccess: ClientAccess{Token: "test-token"},
|
||||
namespace: "default",
|
||||
insecure: false,
|
||||
wantErr: true,
|
||||
errContains: "must provide either a kubeconfig path or a server and token",
|
||||
},
|
||||
{
|
||||
name: "empty namespace is valid",
|
||||
libKubectlAccess: ClientAccess{Token: "test-token", ServerUrl: "https://localhost:6443"},
|
||||
namespace: "",
|
||||
insecure: false,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "insecure true with valid credentials",
|
||||
libKubectlAccess: ClientAccess{Token: "test-token", ServerUrl: "https://localhost:6443"},
|
||||
namespace: "default",
|
||||
insecure: true,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
client, err := NewClient(&tt.libKubectlAccess, tt.namespace, tt.kubeconfig, tt.insecure)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("NewClient() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil && tt.errContains != "" {
|
||||
if got := err.Error(); got != tt.errContains {
|
||||
t.Errorf("NewClient() error = %v, want error containing %v", got, tt.errContains)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if !tt.wantErr {
|
||||
if client == nil {
|
||||
t.Error("NewClient() returned nil client when no error was expected")
|
||||
return
|
||||
}
|
||||
|
||||
// Verify client fields are properly initialized
|
||||
if client.factory == nil {
|
||||
t.Error("NewClient() client.factory is nil")
|
||||
}
|
||||
if client.out == nil {
|
||||
t.Error("NewClient() client.out is nil")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
40
pkg/libkubectl/describe.go
Normal file
40
pkg/libkubectl/describe.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package libkubectl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
describecmd "k8s.io/kubectl/pkg/cmd/describe"
|
||||
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
||||
"k8s.io/kubectl/pkg/describe"
|
||||
)
|
||||
|
||||
// Describe returns the description of a resource
|
||||
// name is the name of the resource, kind is the kind of the resource, and namespace is the namespace of the resource
|
||||
// this is identical to running `kubectl describe <kind> <name> --namespace <namespace>`
|
||||
func (c *Client) Describe(namespace, name, kind string) (string, error) {
|
||||
describeOptions := &describecmd.DescribeOptions{
|
||||
BuilderArgs: []string{kind, name},
|
||||
Describer: func(mapping *meta.RESTMapping) (describe.ResourceDescriber, error) {
|
||||
return describe.DescriberFn(c.factory, mapping)
|
||||
},
|
||||
FilenameOptions: &resource.FilenameOptions{},
|
||||
DescriberSettings: &describe.DescriberSettings{
|
||||
ShowEvents: true,
|
||||
ChunkSize: cmdutil.DefaultChunkSize,
|
||||
},
|
||||
IOStreams: c.streams,
|
||||
NewBuilder: c.factory.NewBuilder,
|
||||
}
|
||||
|
||||
if namespace != "" {
|
||||
describeOptions.Namespace = namespace
|
||||
}
|
||||
|
||||
if err := describeOptions.Run(); err != nil {
|
||||
return "", fmt.Errorf("error describing resources: %w", err)
|
||||
}
|
||||
|
||||
return c.out.String(), nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue