This commit is contained in:
DongYoung Kim 2025-06-23 11:24:24 +02:00 committed by GitHub
commit 5bda94572e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 197 additions and 39 deletions

View File

@ -2,7 +2,7 @@ extend type Query {
"""
Returns experiment run based on experiment run ID
"""
getExperimentRun(projectID: ID!, experimentRunID: ID, notifyID: ID): ExperimentRun!
getExperimentRun(projectID: ID!, experimentRunID: ID, notifyID: ID, infraID: InfraIdentity): ExperimentRun!
"""
Returns the list of experiment run based on various filter parameters

View File

@ -288,6 +288,10 @@ input PodLogRequest {
"""
infraID: ID!
"""
"""
projectID: ID!
"""
ID of a experiment run
"""
experimentRunID: ID!

View File

@ -82,17 +82,33 @@ func (r *mutationResolver) StopExperimentRuns(ctx context.Context, projectID str
}
// GetExperimentRun is the resolver for the getExperimentRun field.
func (r *queryResolver) GetExperimentRun(ctx context.Context, projectID string, experimentRunID *string, notifyID *string) (*model.ExperimentRun, error) {
func (r *queryResolver) GetExperimentRun(ctx context.Context, projectID string, experimentRunID *string, notifyID *string, infraID *model.InfraIdentity) (*model.ExperimentRun, error) {
logFields := logrus.Fields{
"projectId": projectID,
"chaosExperimentRunId": experimentRunID,
"infraID": infraID,
}
logrus.WithFields(logFields).Info("request received to fetch chaos experiment run")
err := authorization.ValidateRole(ctx, projectID,
authorization.MutationRbacRules[authorization.GetWorkflowRun],
model.InvitationAccepted.String())
if err != nil {
return nil, err
// Infrastructure validation
if infraID != nil {
_, err := r.chaosInfrastructureService.VerifyInfra(*infraID)
if err != nil {
logrus.WithFields(logFields).Error(err)
return nil, err
}
// Authorization validation
} else {
err := authorization.ValidateRole(ctx, projectID,
authorization.MutationRbacRules[authorization.GetWorkflowRun],
model.InvitationAccepted.String())
if err != nil {
return nil, err
}
}
expRunResponse, err := r.chaosExperimentRunHandler.GetExperimentRun(ctx, projectID, experimentRunID, notifyID)

View File

@ -607,7 +607,7 @@ type ComplexityRoot struct {
GetChaosHubStats func(childComplexity int, projectID string) int
GetEnvironment func(childComplexity int, projectID string, environmentID string) int
GetExperiment func(childComplexity int, projectID string, experimentID string) int
GetExperimentRun func(childComplexity int, projectID string, experimentRunID *string, notifyID *string) int
GetExperimentRun func(childComplexity int, projectID string, experimentRunID *string, notifyID *string, infraID *model.InfraIdentity) int
GetExperimentRunStats func(childComplexity int, projectID string) int
GetExperimentStats func(childComplexity int, projectID string) int
GetGitOpsDetails func(childComplexity int, projectID string) int
@ -766,7 +766,7 @@ type QueryResolver interface {
GetExperiment(ctx context.Context, projectID string, experimentID string) (*model.GetExperimentResponse, error)
ListExperiment(ctx context.Context, projectID string, request model.ListExperimentRequest) (*model.ListExperimentResponse, error)
GetExperimentStats(ctx context.Context, projectID string) (*model.GetExperimentStatsResponse, error)
GetExperimentRun(ctx context.Context, projectID string, experimentRunID *string, notifyID *string) (*model.ExperimentRun, error)
GetExperimentRun(ctx context.Context, projectID string, experimentRunID *string, notifyID *string, infraID *model.InfraIdentity) (*model.ExperimentRun, error)
ListExperimentRun(ctx context.Context, projectID string, request model.ListExperimentRunRequest) (*model.ListExperimentRunResponse, error)
GetExperimentRunStats(ctx context.Context, projectID string) (*model.GetExperimentRunStatsResponse, error)
GetInfra(ctx context.Context, projectID string, infraID string) (*model.Infra, error)
@ -3729,7 +3729,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
return e.complexity.Query.GetExperimentRun(childComplexity, args["projectID"].(string), args["experimentRunID"].(*string), args["notifyID"].(*string)), true
return e.complexity.Query.GetExperimentRun(childComplexity, args["projectID"].(string), args["experimentRunID"].(*string), args["notifyID"].(*string), args["infraID"].(*model.InfraIdentity)), true
case "Query.getExperimentRunStats":
if e.complexity.Query.GetExperimentRunStats == nil {
@ -5362,7 +5362,7 @@ type Mutation {
"""
Returns experiment run based on experiment run ID
"""
getExperimentRun(projectID: ID!, experimentRunID: ID, notifyID: ID): ExperimentRun!
getExperimentRun(projectID: ID!, experimentRunID: ID, notifyID: ID, infraID: InfraIdentity): ExperimentRun!
"""
Returns the list of experiment run based on various filter parameters
@ -5688,6 +5688,10 @@ input PodLogRequest {
"""
infraID: ID!
"""
"""
projectID: ID!
"""
ID of a experiment run
"""
experimentRunID: ID!
@ -9317,6 +9321,15 @@ func (ec *executionContext) field_Query_getExperimentRun_args(ctx context.Contex
}
}
args["notifyID"] = arg2
var arg3 *model.InfraIdentity
if tmp, ok := rawArgs["infraID"]; ok {
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("infraID"))
arg3, err = ec.unmarshalOInfraIdentity2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐInfraIdentity(ctx, tmp)
if err != nil {
return nil, err
}
}
args["infraID"] = arg3
return args, nil
}
@ -28622,7 +28635,7 @@ func (ec *executionContext) _Query_getExperimentRun(ctx context.Context, field g
}()
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return ec.resolvers.Query().GetExperimentRun(rctx, fc.Args["projectID"].(string), fc.Args["experimentRunID"].(*string), fc.Args["notifyID"].(*string))
return ec.resolvers.Query().GetExperimentRun(rctx, fc.Args["projectID"].(string), fc.Args["experimentRunID"].(*string), fc.Args["notifyID"].(*string), fc.Args["infraID"].(*model.InfraIdentity))
})
if err != nil {
ec.Error(ctx, err)
@ -38042,7 +38055,7 @@ func (ec *executionContext) unmarshalInputPodLogRequest(ctx context.Context, obj
asMap[k] = v
}
fieldsInOrder := [...]string{"infraID", "experimentRunID", "podName", "podNamespace", "podType", "expPod", "runnerPod", "chaosNamespace"}
fieldsInOrder := [...]string{"infraID", "projectID", "experimentRunID", "podName", "podNamespace", "podType", "expPod", "runnerPod", "chaosNamespace"}
for _, k := range fieldsInOrder {
v, ok := asMap[k]
if !ok {
@ -38056,6 +38069,13 @@ func (ec *executionContext) unmarshalInputPodLogRequest(ctx context.Context, obj
return it, err
}
it.InfraID = data
case "projectID":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("projectID"))
data, err := ec.unmarshalNID2string(ctx, v)
if err != nil {
return it, err
}
it.ProjectID = data
case "experimentRunID":
ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("experimentRunID"))
data, err := ec.unmarshalNID2string(ctx, v)
@ -46501,6 +46521,14 @@ func (ec *executionContext) unmarshalOInfraFilterInput2ᚖgithubᚗcomᚋlitmusc
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalOInfraIdentity2ᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐInfraIdentity(ctx context.Context, v interface{}) (*model.InfraIdentity, error) {
if v == nil {
return nil, nil
}
res, err := ec.unmarshalInputInfraIdentity(ctx, v)
return &res, graphql.ErrorOnPath(ctx, err)
}
func (ec *executionContext) unmarshalOInfrastructureType2ᚕᚖgithubᚗcomᚋlitmuschaosᚋlitmusᚋchaoscenterᚋgraphqlᚋserverᚋgraphᚋmodelᚐInfrastructureType(ctx context.Context, v interface{}) ([]*model.InfrastructureType, error) {
if v == nil {
return nil, nil

View File

@ -1663,7 +1663,8 @@ type PodLog struct {
// Defines the details for fetching the pod logs
type PodLogRequest struct {
// ID of the cluster
InfraID string `json:"infraID"`
InfraID string `json:"infraID"`
ProjectID string `json:"projectID"`
// ID of a experiment run
ExperimentRunID string `json:"experimentRunID"`
// Name of the pod for which logs are required

View File

@ -1,8 +1,14 @@
package graphql
import (
"subscriber/pkg/types"
)
type SubscriberGql interface {
SendRequest(server string, payload []byte) (string, error)
MarshalGQLData(gqlData interface{}) (string, error)
SendExperimentRunRuquest(infraData map[string]string, podLog types.PodLogRequest) (types.ExperimentRunResponse, error)
GenerateExperimentRunPayload(cid, accessKey, version string, podLog types.PodLogRequest) ([]byte, error)
}
type subscriberGql struct {

View File

@ -7,6 +7,7 @@ import (
"net/http"
"strconv"
"strings"
"subscriber/pkg/types"
log "github.com/sirupsen/logrus"
)
@ -48,3 +49,32 @@ func (gql *subscriberGql) MarshalGQLData(gqlData interface{}) (string, error) {
processed = strings.Replace(processed, `\"`, `\\\"`, -1)
return processed, nil
}
// Get an experiment run on the GraphQL server
func (gql *subscriberGql) SendExperimentRunRuquest(infraData map[string]string, podLog types.PodLogRequest) (types.ExperimentRunResponse, error) {
payload, _ := gql.GenerateExperimentRunPayload(infraData["INFRA_ID"], infraData["ACCESS_KEY"], infraData["VERSION"], podLog)
body, err := gql.SendRequest(infraData["SERVER_ADDR"], payload)
if err != nil {
log.WithError(err).Print("Failed to send experiment run request")
}
var respsone types.ExperimentRunResponse
err = json.Unmarshal([]byte(body), &respsone)
if err != nil {
log.WithError(err).WithField("data", string(body)).Fatal("Failed to parse ExperimentRun data")
}
log.Print("Response from the server: ", body)
return respsone, nil
}
func (gql *subscriberGql) GenerateExperimentRunPayload(cid, accessKey, version string, podLog types.PodLogRequest) ([]byte, error) {
infraID := `infraID: {infraID: \"` + cid + `\", version: \"` + version + `\", accessKey: \"` + accessKey + `\"}`
query := infraID + `, experimentRunID: \"` + podLog.ExperimentRunID + `\", projectID: \"` + podLog.ProjectID + `\", notifyID: \"\"`
var payload = []byte(`{"query": "query { getExperimentRun(` + query + `) { phase } }"}`)
return payload, nil
}

View File

@ -15,9 +15,11 @@ import (
type SubscriberK8s interface {
GetLogs(podName, namespace, container string) (string, error)
CreatePodLog(podLog types.PodLogRequest) (types.PodLog, error)
GetPodLogs(infraData map[string]string, podLog types.PodLogRequest) (types.PodLog, error)
categorizeLogByPhase(phase string) string
CreatePodLog(infraData map[string]string, logDetails types.PodLog, podLog types.PodLogRequest) (types.PodLog, error)
SendPodLogs(infraData map[string]string, podLog types.PodLogRequest)
GenerateLogPayload(cid, accessKey, version string, podLog types.PodLogRequest) ([]byte, error)
GenerateLogPayload(cid, accessKey, version, processed string, podLog types.PodLogRequest) ([]byte, error)
GetKubernetesNamespaces(request types.KubeNamespaceRequest) ([]*types.KubeNamespace, error)
GetKubernetesObjects(request types.KubeObjRequest) (*types.KubeObject, error)
GetObjectDataByNamespace(namespace string, dynamicClient dynamic.Interface, resourceType schema.GroupVersionResource) ([]types.ObjectData, error)

View File

@ -53,17 +53,7 @@ func (k8s *k8sSubscriber) GetLogs(podName, namespace, container string) (string,
}
// create pod log for normal pods and chaos-engine pods
func (k8s *k8sSubscriber) CreatePodLog(podLog types.PodLogRequest) (types.PodLog, error) {
logDetails := types.PodLog{}
mainLog, err := k8s.GetLogs(podLog.PodName, podLog.PodNamespace, "main")
// try getting argo pod logs
if err != nil {
logrus.Errorf("Failed to get argo pod %v logs, err: %v", podLog.PodName, err)
logDetails.MainPod = "Failed to get argo pod logs"
} else {
logDetails.MainPod = strconv.Quote(strings.Replace(mainLog, `"`, `'`, -1))
logDetails.MainPod = logDetails.MainPod[1 : len(logDetails.MainPod)-1]
}
func (k8s *k8sSubscriber) CreatePodLog(infraData map[string]string, logDetails types.PodLog, podLog types.PodLogRequest) (types.PodLog, error) {
// try getting experiment pod logs if requested
if strings.ToLower(podLog.PodType) == "chaosengine" && podLog.ChaosNamespace != nil {
chaosLog := make(map[string]string)
@ -96,11 +86,21 @@ func (k8s *k8sSubscriber) CreatePodLog(podLog types.PodLogRequest) (types.PodLog
// SendPodLogs generates graphql mutation to send events updates to graphql server
func (k8s *k8sSubscriber) SendPodLogs(infraData map[string]string, podLog types.PodLogRequest) {
// generate graphql payload
payload, err := k8s.GenerateLogPayload(infraData["INFRA_ID"], infraData["ACCESS_KEY"], infraData["VERSION"], podLog)
logDetails, err := k8s.GetPodLogs(infraData, podLog)
if err != nil {
logrus.WithError(err).Print("Error while retrieving the workflow logs")
logrus.WithError(err).Print("failed to get pod logs")
}
// MarashalGQLData
processed, err := k8s.gqlSubscriberServer.MarshalGQLData(logDetails)
if err != nil {
processed = " Could not get logs "
}
// Generate graphql payload
payload, _ := k8s.GenerateLogPayload(infraData["INFRA_ID"], infraData["ACCESS_KEY"], infraData["VERSION"], processed, podLog)
body, err := k8s.gqlSubscriberServer.SendRequest(infraData["SERVER_ADDR"], payload)
if err != nil {
logrus.Print(err.Error())
@ -108,20 +108,62 @@ func (k8s *k8sSubscriber) SendPodLogs(infraData map[string]string, podLog types.
logrus.Print("Response from the server: ", body)
}
func (k8s *k8sSubscriber) GenerateLogPayload(cid, accessKey, version string, podLog types.PodLogRequest) ([]byte, error) {
infraID := `{infraID: \"` + cid + `\", version: \"` + version + `\", accessKey: \"` + accessKey + `\"}`
processed := " Could not get logs "
func (k8s *k8sSubscriber) GetPodLogs(infraData map[string]string, podLog types.PodLogRequest) (types.PodLog, error) {
logDetails := types.PodLog{}
mainLog, err := k8s.GetLogs(podLog.PodName, podLog.PodNamespace, "main")
// try getting argo pod logs
if err != nil {
// fetch ExperimentRun Phase from graphql
experimentRun, _ := k8s.gqlSubscriberServer.SendExperimentRunRuquest(infraData, podLog)
logDetails.MainPod = k8s.categorizeLogByPhase(experimentRun.Data.ExperimentRun.Phase) + " Pod name: " + podLog.PodName
logrus.WithError(err).Print("Failed to get pod logs for attempting to fetch experiment run phase")
} else {
logDetails.MainPod = strconv.Quote(strings.Replace(mainLog, `"`, `'`, -1))
logDetails.MainPod = logDetails.MainPod[1 : len(logDetails.MainPod)-1]
logDetails, err = k8s.CreatePodLog(infraData, logDetails, podLog)
// get the logs
logDetails, err := k8s.CreatePodLog(podLog)
if err == nil {
// process log data
processed, err = k8s.gqlSubscriberServer.MarshalGQLData(logDetails)
if err != nil {
processed = " Could not get logs "
return logDetails, err
}
}
return logDetails, nil
}
// Categorizing log messages by experiment phase
func (k8s *k8sSubscriber) categorizeLogByPhase(phase string) string {
switch phase {
case "Completed":
return "Experiment pod was deleted."
case "Stopped":
return "Experiment is stopped."
case "Running":
return "Experiment pod is initializing."
case "Queue":
return "Queue."
case "NA":
return "NA."
case "Terminated":
return "Terminated."
case "Completed_With_Error":
return "Completed_With_Error."
case "Timeout":
return "Timeout."
case "Error":
return "Experiment could not start."
default:
return "Experiment pod is initializing."
}
}
func (k8s *k8sSubscriber) GenerateLogPayload(cid, accessKey, version, processed string, podLog types.PodLogRequest) ([]byte, error) {
infraID := `{infraID: \"` + cid + `\", version: \"` + version + `\", accessKey: \"` + accessKey + `\"}`
mutation := `{ infraID: ` + infraID + `, requestID:\"` + podLog.RequestID + `\", experimentRunID: \"` + podLog.ExperimentRunID + `\", podName: \"` + podLog.PodName + `\", podType: \"` + podLog.PodType + `\", log:\"` + processed[1:len(processed)-1] + `\"}`
var payload = []byte(`{"query":"mutation { podLog(request:` + mutation + ` )}"}`)

View File

@ -0,0 +1,13 @@
package types
type ExperimentRunResponse struct {
Data ExperimentRun `json:"data"`
}
type ExperimentRun struct {
ExperimentRun Phase `json:"getExperimentRun"`
}
type Phase struct {
Phase string `json:"phase"`
}

View File

@ -2,6 +2,7 @@ package types
type PodLogRequest struct {
RequestID string `json:"requestID"`
ProjectID string `json:"projectID"`
InfraID string `json:"infraID"`
ExperimentRunID string `json:"experimentRunID"`
PodName string `json:"podName"`

View File

@ -14,6 +14,7 @@ interface GetPodLogsRequest {
request: {
// requestID: string;
infraID: string;
projectID: string;
experimentRunID?: string;
podName: string;
podNamespace: string;
@ -43,6 +44,7 @@ export function getPodLogsSubscription({
variables: {
request: {
infraID: request.infraID,
projectID: request.projectID,
experimentRunID: request.experimentRunID,
podName: request.podName,
podNamespace: request.podNamespace,

View File

@ -11,6 +11,7 @@ interface CustomStepLogControllerProps {
namespace: string | undefined;
workflowRunID: string | undefined;
infraID: string | undefined;
projectID: string | undefined;
podName: string;
requestID: string;
phase: ExperimentRunStatus | undefined;
@ -19,6 +20,7 @@ interface CustomStepLogControllerProps {
export default function CustomStepLogController({
workflowRunID,
infraID,
projectID,
podName,
chaosData,
nodeType,
@ -36,6 +38,7 @@ export default function CustomStepLogController({
...scope,
infraID: infraID ?? '',
// requestID: requestID,
projectID: projectID ?? '',
experimentRunID: workflowRunID,
podName: podName,
podNamespace: namespace ?? '',

View File

@ -7,6 +7,7 @@ interface LogsTabControllerProps {
nodeType: string | undefined;
chaosData: ChaosData | undefined;
infraID: string | undefined;
projectID: string | undefined;
workflowRunID: string | undefined;
podID: string;
experimentPod?: string;

View File

@ -198,6 +198,7 @@ export default function ExperimentRunDetailsView({
namespace={experimentExecutionDetails?.namespace}
probeData={probeData}
infraID={infra?.infraID}
projectID={scope.projectID}
setSelectedNodeID={setSelectedNodeID}
experimentRunID={experimentRunID}
podID={selectedNodeID}

View File

@ -31,6 +31,7 @@ interface DetailsTabProps {
probeData: ProbeInRuns[] | undefined;
experimentRunID: string | undefined;
infraID: string | undefined;
projectID: string | undefined;
namespace: string | undefined;
phase: ExperimentRunStatus | undefined;
podID: string;
@ -44,6 +45,7 @@ const DetailsTabs = ({
phase,
experimentRunID,
infraID,
projectID,
podID,
manifest,
probeData,
@ -88,6 +90,7 @@ const DetailsTabs = ({
phase={phase}
workflowRunID={experimentRunID}
infraID={infraID}
projectID={projectID}
podID={podID}
/>
)
@ -110,6 +113,7 @@ const ExperimentRunDetailsPanel = ({
phase,
namespace,
infraID,
projectID,
probeData,
podID,
manifest,
@ -261,6 +265,7 @@ const ExperimentRunDetailsPanel = ({
probeData={probeData}
experimentRunID={experimentRunID}
infraID={infraID}
projectID={projectID}
loading={loading}
phase={phase}
namespace={namespace}

View File

@ -10,6 +10,7 @@ interface LogsTabViewProps {
nodeType: string | undefined;
chaosData: ChaosData | undefined;
infraID: string | undefined;
projectID: string | undefined;
workflowRunID: string | undefined;
podID: string;
requestID: string;
@ -22,6 +23,7 @@ export default function LogsTabView({
nodeType,
chaosData,
infraID,
projectID,
workflowRunID,
podID,
requestID,
@ -37,6 +39,7 @@ export default function LogsTabView({
nodeType={nodeType}
namespace={namespace}
infraID={infraID}
projectID={projectID}
requestID={requestID}
workflowRunID={workflowRunID}
podName={podID}