argo by kube invocation
This commit is contained in:
26
tools/interface.go
Normal file
26
tools/interface.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Tool interface {
|
||||
CreateArgoWorkflow(path string) error
|
||||
CreateAccessSecret(ns string, login string, password string) (string, error)
|
||||
LogWorkflow(namespace string, workflowName string, argoFilePath string, stepMax int,
|
||||
logFunc func(argoFilePath string, stepMax int, pipe io.ReadCloser, wg *sync.WaitGroup)) error
|
||||
}
|
||||
|
||||
var _service = map[string]func() (Tool, error){
|
||||
"kubernetes": NewKubernetesTool,
|
||||
}
|
||||
|
||||
func NewService(name string) (Tool, error) {
|
||||
service, ok := _service[name]
|
||||
if !ok {
|
||||
return nil, errors.New("service not found")
|
||||
}
|
||||
return service()
|
||||
}
|
159
tools/kubernetes.go
Normal file
159
tools/kubernetes.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"oc-monitord/conf"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1"
|
||||
"github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned"
|
||||
"github.com/google/uuid"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type KubernetesTools struct {
|
||||
Set *kubernetes.Clientset
|
||||
VersionedSet *versioned.Clientset
|
||||
}
|
||||
|
||||
func NewKubernetesTool() (Tool, error) {
|
||||
// Load Kubernetes config (from ~/.kube/config)
|
||||
config := &rest.Config{
|
||||
Host: conf.GetConfig().KubeHost + ":" + conf.GetConfig().KubePort,
|
||||
TLSClientConfig: rest.TLSClientConfig{
|
||||
CAData: []byte(conf.GetConfig().KubeCA),
|
||||
CertData: []byte(conf.GetConfig().KubeCert),
|
||||
KeyData: []byte(conf.GetConfig().KubeData),
|
||||
},
|
||||
}
|
||||
|
||||
// Create clientset
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.New("Error creating Kubernetes client: " + err.Error())
|
||||
}
|
||||
|
||||
clientset2, err := versioned.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, errors.New("Error creating Kubernetes versionned client: " + err.Error())
|
||||
}
|
||||
return &KubernetesTools{
|
||||
Set: clientset,
|
||||
VersionedSet: clientset2,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (k *KubernetesTools) LogWorkflow(namespace string, workflowName string, argoFilePath string, stepMax int,
|
||||
logFunc func(argoFilePath string, stepMax int, pipe io.ReadCloser, wg *sync.WaitGroup)) error {
|
||||
// List pods related to the Argo workflow
|
||||
labelSelector := fmt.Sprintf("workflows.argoproj.io/workflow=%s", workflowName)
|
||||
pods, err := k.Set.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{
|
||||
LabelSelector: labelSelector,
|
||||
})
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to list pods: %v", err))
|
||||
}
|
||||
|
||||
if len(pods.Items) == 0 {
|
||||
return errors.New("no pods found for the workflow")
|
||||
}
|
||||
var wg *sync.WaitGroup
|
||||
// Stream logs from all matching pods
|
||||
wg.Add(len(pods.Items))
|
||||
for _, pod := range pods.Items {
|
||||
for _, container := range pod.Spec.Containers {
|
||||
fmt.Printf("streaming logs for Pod: %s, Container: %s\n", pod.Name, container.Name)
|
||||
go k.streamLogs(namespace, pod.Name, container.Name, argoFilePath, stepMax, wg, logFunc)
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Function to stream logs
|
||||
func (k *KubernetesTools) streamLogs(namespace string, podName string, containerName string,
|
||||
argoFilePath string, stepMax int, wg *sync.WaitGroup,
|
||||
logFunc func(argo_file_path string, stepMax int, pipe io.ReadCloser, wg *sync.WaitGroup)) {
|
||||
req := k.Set.CoreV1().Pods(namespace).GetLogs(podName, &corev1.PodLogOptions{
|
||||
Container: containerName,
|
||||
Follow: true, // Equivalent to -f flag in kubectl logs
|
||||
})
|
||||
|
||||
// Open stream
|
||||
stream, err := req.Stream(context.TODO())
|
||||
if err != nil {
|
||||
fmt.Printf("Error opening log stream for pod %s: %v\n", podName, err)
|
||||
return
|
||||
}
|
||||
defer stream.Close()
|
||||
logFunc(argoFilePath, stepMax, stream, wg)
|
||||
}
|
||||
|
||||
func (k *KubernetesTools) CreateArgoWorkflow(path string) error {
|
||||
// Read workflow YAML file
|
||||
workflowYAML, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Decode the YAML into a Workflow struct
|
||||
scheme := runtime.NewScheme()
|
||||
_ = wfv1.AddToScheme(scheme)
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
decode := codecs.UniversalDeserializer().Decode
|
||||
|
||||
obj, _, err := decode(workflowYAML, nil, nil)
|
||||
if err != nil {
|
||||
return errors.New("failed to decode YAML: " + err.Error())
|
||||
}
|
||||
|
||||
workflow, ok := obj.(*wfv1.Workflow)
|
||||
if !ok {
|
||||
return errors.New("decoded object is not a Workflow")
|
||||
}
|
||||
|
||||
// Create the workflow in the "argo" namespace
|
||||
createdWf, err := k.VersionedSet.ArgoprojV1alpha1().Workflows("argo").Create(context.TODO(), workflow, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return errors.New("failed to create workflow: " + err.Error())
|
||||
}
|
||||
fmt.Printf("workflow %s created in namespace %s\n", createdWf.Name, "argo")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *KubernetesTools) CreateAccessSecret(ns string, login string, password string) (string, error) {
|
||||
// Namespace where the secret will be created
|
||||
namespace := "default"
|
||||
// Encode the secret data (Kubernetes requires base64-encoded values)
|
||||
secretData := map[string][]byte{
|
||||
"access-key": []byte(base64.StdEncoding.EncodeToString([]byte(login))),
|
||||
"secret-key": []byte(base64.StdEncoding.EncodeToString([]byte(password))),
|
||||
}
|
||||
|
||||
// Define the Secret object
|
||||
name := uuid.New().String()
|
||||
secret := &v1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: ns,
|
||||
},
|
||||
Type: v1.SecretTypeOpaque,
|
||||
Data: secretData,
|
||||
}
|
||||
// Create the Secret in Kubernetes
|
||||
_, err := k.Set.CoreV1().Secrets(namespace).Create(context.TODO(), secret, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return "", errors.New("Error creating secret: " + err.Error())
|
||||
}
|
||||
return name, nil
|
||||
}
|
Reference in New Issue
Block a user