mirror of
https://github.com/foomo/squadron.git
synced 2025-10-16 12:35:42 +00:00
223 lines
5.7 KiB
Go
223 lines
5.7 KiB
Go
package util
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/pkg/errors"
|
|
k8s "k8s.io/api/apps/v1"
|
|
)
|
|
|
|
type KubeCmd struct {
|
|
Cmd
|
|
}
|
|
|
|
func NewKubeCommand() *KubeCmd {
|
|
return &KubeCmd{*NewCommand("kubectl")}
|
|
}
|
|
|
|
func (c KubeCmd) RollbackDeployment(deployment string) *Cmd {
|
|
return c.Args("rollout", "undo", fmt.Sprintf("deployment/%v", deployment))
|
|
}
|
|
|
|
func (c KubeCmd) WaitForRollout(deployment, timeout string) *Cmd {
|
|
return c.Args("rollout", "status", fmt.Sprintf("deployment/%v", deployment),
|
|
"-w", "--timeout", timeout)
|
|
}
|
|
|
|
func (c KubeCmd) GetMostRecentPodBySelectors(ctx context.Context, selectors map[string]string) (string, error) {
|
|
var selector []string //nolint:prealloc
|
|
for k, v := range selectors {
|
|
selector = append(selector, fmt.Sprintf("%v=%v", k, v))
|
|
}
|
|
|
|
out, err := c.Args("--selector", strings.Join(selector, ","),
|
|
"get", "pods", "--sort-by=.status.startTime", "-o", "name").Run(ctx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
pods, err := parseResources(out, "pod/")
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
if len(pods) > 0 {
|
|
return pods[len(pods)-1], nil
|
|
}
|
|
|
|
return "", errors.New("no pods found")
|
|
}
|
|
|
|
func (c KubeCmd) WaitForPodState(pod, condition, timeout string) *Cmd {
|
|
return c.Args("wait", fmt.Sprintf("pod/%v", pod),
|
|
fmt.Sprintf("--for=%v", condition),
|
|
fmt.Sprintf("--timeout=%v", timeout))
|
|
}
|
|
|
|
func (c KubeCmd) ExecShell(resource, path string) *Cmd {
|
|
return c.Args("exec", "-it", resource,
|
|
"--", "/bin/sh", "-c",
|
|
fmt.Sprintf("cd %v && /bin/sh", path),
|
|
).Stdin(os.Stdin).Stdout(os.Stdout).Stderr(os.Stdout)
|
|
}
|
|
|
|
func (c KubeCmd) PatchDeployment(patch, deployment string) *Cmd {
|
|
return c.Args("patch", "deployment", deployment, "--patch", patch)
|
|
}
|
|
|
|
func (c KubeCmd) CopyToPod(pod, container, source, destination string) *Cmd {
|
|
return c.Args("cp", source, fmt.Sprintf("%v:%v", pod, destination), "-c", container)
|
|
}
|
|
|
|
func (c KubeCmd) ExecPod(pod, container string, cmd []string) *Cmd {
|
|
return c.Args("exec", pod, "-c", container, "--").Args(cmd...)
|
|
}
|
|
|
|
func (c KubeCmd) ExposePod(pod string, host string, port int) *Cmd {
|
|
if host == "127.0.0.1" {
|
|
host = ""
|
|
}
|
|
|
|
return c.Args("expose", "pod", pod, "--type=LoadBalancer",
|
|
fmt.Sprintf("--port=%v", port), fmt.Sprintf("--external-ip=%v", host))
|
|
}
|
|
|
|
func (c KubeCmd) DeleteService(service string) *Cmd {
|
|
return c.Args("delete", "service", service)
|
|
}
|
|
|
|
func (c KubeCmd) GetDeployment(ctx context.Context, deployment string) (*k8s.Deployment, error) {
|
|
out, err := c.Args("get", "deployment", deployment, "-o", "json").Run(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var d k8s.Deployment
|
|
if err := json.Unmarshal([]byte(out), &d); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &d, nil
|
|
}
|
|
|
|
func (c KubeCmd) GetNamespaces(ctx context.Context) ([]string, error) {
|
|
out, err := c.Args("get", "namespace", "-o", "name").Run(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return parseResources(out, "namespace/")
|
|
}
|
|
|
|
func (c KubeCmd) GetDeployments(ctx context.Context) ([]string, error) {
|
|
out, err := c.Args("get", "deployment", "-o", "name").Run(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return parseResources(out, "deployment.apps/")
|
|
}
|
|
|
|
func (c KubeCmd) GetPods(ctx context.Context, selectors map[string]string) ([]string, error) {
|
|
var selector []string //nolint:prealloc
|
|
for k, v := range selectors {
|
|
selector = append(selector, fmt.Sprintf("%v=%v", k, v))
|
|
}
|
|
|
|
out, err := c.Args("--selector", strings.Join(selector, ","),
|
|
"get", "pods", "--sort-by=.status.startTime",
|
|
"-o", "name").Run(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return parseResources(out, "pod/")
|
|
}
|
|
|
|
func (c KubeCmd) GetContainers(deployment k8s.Deployment) []string {
|
|
containers := make([]string, len(deployment.Spec.Template.Spec.Containers))
|
|
for i, c := range deployment.Spec.Template.Spec.Containers {
|
|
containers[i] = c.Name
|
|
}
|
|
|
|
return containers
|
|
}
|
|
|
|
func (c KubeCmd) GetPodsByLabels(ctx context.Context, labels []string) ([]string, error) {
|
|
out, err := c.Args("get", "pods", "-l", strings.Join(labels, ","), "-o", "name", "-A").Run(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return parseResources(out, "pod/")
|
|
}
|
|
|
|
func (c KubeCmd) RestartDeployment(deployment string) *Cmd {
|
|
return c.Args("rollout", "restart", fmt.Sprintf("deployment/%v", deployment))
|
|
}
|
|
|
|
func (c KubeCmd) CreateConfigMapFromFile(ctx context.Context, name, path string) (string, error) {
|
|
return c.Args("create", "configmap", name, "--from-file", path).Run(ctx)
|
|
}
|
|
|
|
func (c KubeCmd) CreateConfigMap(ctx context.Context, name string, keyMap map[string]string) (string, error) {
|
|
c.Args("create", "configmap", name)
|
|
|
|
for key, value := range keyMap {
|
|
c.Args(fmt.Sprintf("--from-literal=%v=%v", key, value))
|
|
}
|
|
|
|
return c.Run(ctx)
|
|
}
|
|
|
|
func (c KubeCmd) DeleteConfigMap(ctx context.Context, name string) (string, error) {
|
|
return c.Args("delete", "configmap", name).Run(ctx)
|
|
}
|
|
|
|
func (c KubeCmd) GetConfigMapKey(ctx context.Context, name, key string) (string, error) {
|
|
key = strings.ReplaceAll(key, ".", "\\.")
|
|
// jsonpath map key is not very fond of dots
|
|
out, err := c.Args("get", "configmap", name, "-o",
|
|
fmt.Sprintf("jsonpath={.data.%v}", key)).Run(ctx)
|
|
if err != nil {
|
|
return out, err
|
|
}
|
|
|
|
if out == "" {
|
|
return out, fmt.Errorf("no key %q found in ConfigMap %q", key, name)
|
|
}
|
|
|
|
return out, nil
|
|
}
|
|
|
|
func parseResources(out, prefix string) ([]string, error) {
|
|
var res []string //nolint:prealloc
|
|
if out == "" {
|
|
return res, nil
|
|
}
|
|
|
|
lines := strings.Split(out, "\n")
|
|
if len(lines) == 1 && lines[0] == "" {
|
|
return nil, fmt.Errorf("delimiter %q not found in %q", "\n", out)
|
|
}
|
|
|
|
for _, line := range lines {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
|
|
unprefixed := strings.TrimPrefix(line, prefix)
|
|
if unprefixed == line {
|
|
return nil, fmt.Errorf("prefix %q not found in %q", prefix, line)
|
|
}
|
|
|
|
res = append(res, strings.TrimPrefix(line, prefix))
|
|
}
|
|
|
|
return res, nil
|
|
}
|