Skip to content

Commit

Permalink
Merge pull request #564 from replicatedhq/diamonwiggins/sc-44286/run-…
Browse files Browse the repository at this point in the history
…pod-spec

RunPod Collector
  • Loading branch information
diamonwiggins authored May 6, 2022
2 parents 2c9a37a + 9f527ee commit d6a1795
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 69 deletions.
28 changes: 28 additions & 0 deletions pkg/apis/troubleshoot/v1beta2/collector_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/replicatedhq/troubleshoot/pkg/multitype"
authorizationv1 "k8s.io/api/authorization/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand Down Expand Up @@ -77,6 +78,15 @@ type Run struct {
ServiceAccountName string `json:"serviceAccountName,omitempty" yaml:"serviceAccountName,omitempty"`
}

type RunPod struct {
CollectorMeta `json:",inline" yaml:",inline"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Namespace string `json:"namespace" yaml:"namespace"`
Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"`
ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"`
PodSpec corev1.PodSpec `json:"podSpec,omitempty" yaml:"podSpec,omitempty"`
}

type ImagePullSecrets struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"`
Expand Down Expand Up @@ -196,6 +206,7 @@ type Collect struct {
ConfigMap *ConfigMap `json:"configMap,omitempty" yaml:"configMap,omitempty"`
Logs *Logs `json:"logs,omitempty" yaml:"logs,omitempty"`
Run *Run `json:"run,omitempty" yaml:"run,omitempty"`
RunPod *RunPod `json:"runPod,omitempty" yaml:"runPod,omitempty"`
Exec *Exec `json:"exec,omitempty" yaml:"exec,omitempty"`
Data *Data `json:"data,omitempty" yaml:"data,omitempty"`
Copy *Copy `json:"copy,omitempty" yaml:"copy,omitempty"`
Expand Down Expand Up @@ -329,6 +340,19 @@ func (c *Collect) AccessReviewSpecs(overrideNS string) []authorizationv1.SelfSub
},
NonResourceAttributes: nil,
})
} else if c.RunPod != nil {
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: pickNamespaceOrDefault(c.RunPod.Namespace, overrideNS),
Verb: "create",
Group: "",
Version: "",
Resource: "pods",
Subresource: "",
Name: "",
},
NonResourceAttributes: nil,
})
} else if c.Exec != nil {
result = append(result, authorizationv1.SelfSubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Expand Down Expand Up @@ -434,6 +458,10 @@ func (c *Collect) GetName() string {
collector = "run"
name = c.Run.CollectorName
}
if c.RunPod != nil {
collector = "run-pod"
name = c.RunPod.CollectorName
}
if c.Exec != nil {
collector = "exec"
name = c.Exec.CollectorName
Expand Down
27 changes: 27 additions & 0 deletions pkg/apis/troubleshoot/v1beta2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions pkg/collect/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ func (c *Collector) IsExcluded() bool {
if isExcludedResult {
return true
}
} else if c.Collect.RunPod != nil {
isExcludedResult, err := isExcluded(c.Collect.RunPod.Exclude)
if err != nil {
return true
}
if isExcludedResult {
return true
}
} else if c.Collect.Exec != nil {
isExcludedResult, err := isExcluded(c.Collect.Exec.Exclude)
if err != nil {
Expand Down Expand Up @@ -225,6 +233,8 @@ func (c *Collector) RunCollectorSync(clientConfig *rest.Config, client kubernete
result, err = Logs(c, c.Collect.Logs)
} else if c.Collect.Run != nil {
result, err = Run(c, c.Collect.Run)
} else if c.Collect.RunPod != nil {
result, err = RunPod(c, c.Collect.RunPod)
} else if c.Collect.Exec != nil {
result, err = Exec(c, c.Collect.Exec)
} else if c.Collect.Data != nil {
Expand Down
166 changes: 97 additions & 69 deletions pkg/collect/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,53 @@ import (
)

func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult, error) {
pullPolicy := corev1.PullIfNotPresent
if runCollector.ImagePullPolicy != "" {
pullPolicy = corev1.PullPolicy(runCollector.ImagePullPolicy)
}

namespace := "default"
if runCollector.Namespace != "" {
namespace = runCollector.Namespace
}

serviceAccountName := "default"
if runCollector.ServiceAccountName != "" {
serviceAccountName = runCollector.ServiceAccountName
}

runPodCollector := &troubleshootv1beta2.RunPod{
Name: runCollector.CollectorName,
Namespace: namespace,
Timeout: runCollector.Timeout,
ImagePullSecret: runCollector.ImagePullSecret,
PodSpec: corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: serviceAccountName,
Containers: []corev1.Container{
{
Image: runCollector.Image,
ImagePullPolicy: pullPolicy,
Name: "collector",
Command: runCollector.Command,
Args: runCollector.Args,
},
},
},
}

return RunPod(c, runPodCollector)
}

func RunPod(c *Collector, runPodCollector *troubleshootv1beta2.RunPod) (CollectorResult, error) {
ctx := context.Background()

client, err := kubernetes.NewForConfig(c.ClientConfig)
if err != nil {
return nil, errors.Wrap(err, "failed to create client from config")
}

pod, err := runPod(ctx, client, runCollector, c.Namespace)
pod, err := runPodWithSpec(ctx, client, runPodCollector)
if err != nil {
return nil, errors.Wrap(err, "failed to run pod")
}
Expand All @@ -33,7 +72,7 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
logger.Printf("Failed to delete pod %s: %v", pod.Name, err)
}
}()
if runCollector.ImagePullSecret != nil && runCollector.ImagePullSecret.Data != nil {
if runPodCollector.ImagePullSecret != nil && runPodCollector.ImagePullSecret.Data != nil {
defer func() {
for _, k := range pod.Spec.ImagePullSecrets {
if err := client.CoreV1().Secrets(pod.Namespace).Delete(ctx, k.Name, metav1.DeleteOptions{}); err != nil {
Expand All @@ -42,11 +81,11 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
}
}()
}
if runCollector.Timeout == "" {
return runWithoutTimeout(ctx, c, pod, runCollector)
if runPodCollector.Timeout == "" {
return runWithoutTimeout(ctx, c, pod, runPodCollector)
}

timeout, err := time.ParseDuration(runCollector.Timeout)
timeout, err := time.ParseDuration(runPodCollector.Timeout)
if err != nil {
return nil, errors.Wrap(err, "failed to parse timeout")
}
Expand All @@ -58,7 +97,7 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
defer cancel()

go func() {
b, err := runWithoutTimeout(timeoutCtx, c, pod, runCollector)
b, err := runWithoutTimeout(timeoutCtx, c, pod, runPodCollector)
if err != nil {
errCh <- err
} else {
Expand All @@ -76,7 +115,52 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (CollectorResult,
}
}

func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runCollector *troubleshootv1beta2.Run) (CollectorResult, error) {
func runPodWithSpec(ctx context.Context, client *kubernetes.Clientset, runPodCollector *troubleshootv1beta2.RunPod) (*corev1.Pod, error) {
podLabels := make(map[string]string)
podLabels["troubleshoot-role"] = "run-collector"

namespace := "default"
if runPodCollector.Namespace != "" {
namespace = runPodCollector.Namespace
}

podName := "run-pod"
if runPodCollector.CollectorName != "" {
podName = runPodCollector.CollectorName
} else if runPodCollector.Name != "" {
podName = runPodCollector.Name
}

pod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: podName,
Namespace: namespace,
Labels: podLabels,
},
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Pod",
},
Spec: runPodCollector.PodSpec,
}

if runPodCollector.ImagePullSecret != nil && runPodCollector.ImagePullSecret.Data != nil {
secretName, err := createSecret(ctx, client, pod.Namespace, runPodCollector.ImagePullSecret)
if err != nil {
return nil, errors.Wrap(err, "failed to create secret")
}
pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: secretName})
}

created, err := client.CoreV1().Pods(namespace).Create(ctx, &pod, metav1.CreateOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed to create pod")
}

return created, nil
}

func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runPodCollector *troubleshootv1beta2.RunPod) (CollectorResult, error) {
client, err := kubernetes.NewForConfig(c.ClientConfig)
if err != nil {
return nil, errors.Wrap(err, "failed create client from config")
Expand Down Expand Up @@ -104,10 +188,15 @@ func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runCo

output := NewResult()

collectorName := runPodCollector.Name
if collectorName == "" {
collectorName = runPodCollector.CollectorName
}

limits := troubleshootv1beta2.LogLimits{
MaxLines: 10000,
}
podLogs, err := savePodLogs(ctx, c.BundlePath, client, *pod, runCollector.Name, "", &limits, true)
podLogs, err := savePodLogs(ctx, c.BundlePath, client, *pod, collectorName, "", &limits, true)
if err != nil {
return nil, errors.Wrap(err, "failed to get pod logs")
}
Expand All @@ -119,67 +208,6 @@ func runWithoutTimeout(ctx context.Context, c *Collector, pod *corev1.Pod, runCo
return output, nil
}

func runPod(ctx context.Context, client *kubernetes.Clientset, runCollector *troubleshootv1beta2.Run, namespace string) (*corev1.Pod, error) {
podLabels := make(map[string]string)
podLabels["troubleshoot-role"] = "run-collector"

pullPolicy := corev1.PullIfNotPresent
if runCollector.ImagePullPolicy != "" {
pullPolicy = corev1.PullPolicy(runCollector.ImagePullPolicy)
}

if namespace == "" {
namespace = runCollector.Namespace
}
if namespace == "" {
namespace = "default"
}

serviceAccountName := "default"
if runCollector.ServiceAccountName != "" {
serviceAccountName = runCollector.ServiceAccountName
}

pod := corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: runCollector.CollectorName,
Namespace: namespace,
Labels: podLabels,
},
TypeMeta: metav1.TypeMeta{
APIVersion: "v1",
Kind: "Pod",
},
Spec: corev1.PodSpec{
RestartPolicy: corev1.RestartPolicyNever,
ServiceAccountName: serviceAccountName,
Containers: []corev1.Container{
{
Image: runCollector.Image,
ImagePullPolicy: pullPolicy,
Name: "collector",
Command: runCollector.Command,
Args: runCollector.Args,
},
},
},
}

if runCollector.ImagePullSecret != nil && runCollector.ImagePullSecret.Data != nil {
secretName, err := createSecret(ctx, client, pod.Namespace, runCollector.ImagePullSecret)
if err != nil {
return nil, errors.Wrap(err, "failed to create secret")
}
pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: secretName})
}
created, err := client.CoreV1().Pods(namespace).Create(ctx, &pod, metav1.CreateOptions{})
if err != nil {
return nil, errors.Wrap(err, "failed to create pod")
}

return created, nil
}

func createSecret(ctx context.Context, client kubernetes.Interface, namespace string, imagePullSecret *troubleshootv1beta2.ImagePullSecrets) (string, error) {
if imagePullSecret.Data == nil {
return "", nil
Expand Down

0 comments on commit d6a1795

Please sign in to comment.