Skip to content

Commit

Permalink
Troubleshooting guide for the validating webhook. (#332)
Browse files Browse the repository at this point in the history
* Troubleshooting guide for the validating webhook.

Signed-off-by: ichbinblau <theresa.shan@intel.com>
  • Loading branch information
ichbinblau authored Aug 21, 2024
1 parent 3b5f62e commit b47ec0c
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 11 deletions.
4 changes: 4 additions & 0 deletions microservices-connector/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,7 @@ make undeploy
### Deploy using helm chart

Please refer to the [helm chart README](./helm/README.md) for deploying GMC using helm chart.

### Troubleshooting guide

Please refer to this [troubleshooting_guide](./troubleshooting_guide.md) for identifying GMC Custom Resource issues.
21 changes: 14 additions & 7 deletions microservices-connector/api/v1alpha3/validating_webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
"TeiReranking",
"Tgi",
"TgiGaudi",
"TgiNvidia",
"Llm",
"DocSum",
"Router",
Expand Down Expand Up @@ -110,12 +111,16 @@ func (r *GMConnector) checkfields() field.ErrorList {
return allErrs
}

func checkStepName(s Step, fldRoot *field.Path, nodeName string) *field.Error {
func checkStepName(s Step, idx int, fldRoot *field.Path, nodeName string) *field.Error {
if len(s.StepName) == 0 {
return field.Invalid(fldRoot.Child(nodeName).Child("stepName"), s, fmt.Sprintf("the step name for node %v cannot be empty", nodeName))
return field.Invalid(fldRoot.Child(nodeName).Child(fmt.Sprintf("steps[%d]", idx)).Child("name"),
s,
fmt.Sprintf("the step name for node %v cannot be empty", nodeName))
}
if !slices.Contains(stepNames, s.StepName) {
return field.Invalid(fldRoot.Child(nodeName).Child("stepName"), s, fmt.Sprintf("invalid step name: %s for node %v", s.StepName, nodeName))
return field.Invalid(fldRoot.Child(nodeName).Child(fmt.Sprintf("steps[%d]", idx)).Child("name"),
s,
fmt.Sprintf("invalid step name: %s for node %v", s.StepName, nodeName))
}
return nil
}
Expand Down Expand Up @@ -143,20 +148,22 @@ func validateNames(nodes map[string]Router, fldPath *field.Path) field.ErrorList
var errs field.ErrorList

for name, router := range nodes {
for _, step := range router.Steps {
for idx, step := range router.Steps {
// validate step name
if err := checkStepName(step, fldPath, name); err != nil {
if err := checkStepName(step, idx, fldPath, name); err != nil {
errs = append(errs, err)
}

// check node name has been defined in the spec
if !nodeNameExists(step.NodeName, nodeNames) {
errs = append(errs, field.Invalid(fldPath.Child(name).Child("nodeName"), step, fmt.Sprintf("node name: %v in step %v does not exist", step.NodeName, step.StepName)))
errs = append(errs, field.Invalid(fldPath.Child(name).Child(fmt.Sprintf("steps[%d]", idx)).Child("nodeName"),
step,
fmt.Sprintf("node name: %v in step %v does not exist", step.NodeName, step.StepName)))
}

// check service name uniqueness
if len(step.InternalService.ServiceName) != 0 && slices.Contains(serviceNames, step.InternalService.ServiceName) {
errs = append(errs, field.Invalid(fldPath.Child(name).Child("internalService").Child("serviceName"),
errs = append(errs, field.Invalid(fldPath.Child(name).Child(fmt.Sprintf("steps[%d]", idx)).Child("internalService").Child("serviceName"),
step,
fmt.Sprintf("service name: %v in node %v already exists", step.InternalService.ServiceName, name)))
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func Test_checkStepName(t *testing.T) {
nodeName: testNode,
},
want: field.Invalid(
field.NewPath("spec").Child("nodes").Child("test-node").Child("stepName"),
field.NewPath("spec").Child("nodes").Child(testNode).Child("steps[0]").Child("name"),
Step{},
fmt.Sprintf("the step name for node %v cannot be empty", testNode),
),
Expand All @@ -135,7 +135,7 @@ func Test_checkStepName(t *testing.T) {
nodeName: testNode,
},
want: field.Invalid(
field.NewPath("spec").Child("nodes").Child("test-node").Child("stepName"),
field.NewPath("spec").Child("nodes").Child(testNode).Child("steps[0]").Child("name"),
Step{
StepName: "invalid",
Executor: Executor{},
Expand All @@ -158,7 +158,7 @@ func Test_checkStepName(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := checkStepName(tt.args.s, tt.args.fldRoot, tt.args.nodeName); !reflect.DeepEqual(got, tt.want) {
if got := checkStepName(tt.args.s, 0, tt.args.fldRoot, tt.args.nodeName); !reflect.DeepEqual(got, tt.want) {
t.Errorf("checkStepName() = %v, want %v", got, tt.want)
}
})
Expand Down Expand Up @@ -323,7 +323,7 @@ func Test_validateNames(t *testing.T) {
fldPath: field.NewPath("spec").Child("nodes"),
},
want: append(errs, field.Invalid(
field.NewPath("spec").Child("nodes").Child("root").Child("internalService").Child("serviceName"),
field.NewPath("spec").Child("nodes").Child("root").Child("steps[1]").Child("internalService").Child("serviceName"),
Step{
StepName: "Embedding",
Executor: Executor{
Expand Down
36 changes: 36 additions & 0 deletions microservices-connector/troubleshooting_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Troubleshooting GMC Custom Resource(CR)

This doc is about identifying issues in GMC CR; A validating webhook has been configured to validate CR fields and it will report all detected errors.
After the CR for GMC pipeline has been deployed, correct the CR if you encounter the following errors:

1. Root node existence

```
The GMCConnector "chatqa" is invalid: spec.nodes: Invalid value: map[string]v1alpha3.Router{"node1":...}: a root node is required
```

In the `spec.nodes` section of the CR, a node with the name ‘root’ is required.

2. StepName validation

```
The GMCConnector "chatqa" is invalid: spec.nodes.root.steps[0].name: Invalid value: v1alpha3.Step{StepName:"Embedding123", Executor:v1alpha3.Executor{NodeName:"", InternalService:v1alpha3.GMCTarget{ServiceName:"embedding-svc", NameSpace:"", Config:map[string]string{"TEI_EMBEDDING_ENDPOINT":"tei-embedding-svc", "endpoint":"/v1/embeddings"}, IsDownstreamService:false}, ExternalService:""}, Data:"", Condition:"", Dependency:"", ServiceURL:""}: invalid step name: Embedding123 for node root
```

In the CR, the value of StepName in the `spec.nodes.<nodeName>.steps[].name` field should be included in the predefined [list](./api/v1alpha3/validating_webhook.go).

3. nodeName existence

```
The GMCConnector "switch" is invalid: spec.nodes.root.steps[0].nodeName: Invalid value: v1alpha3.Step{StepName:"Embedding", Executor:v1alpha3.Executor{NodeName:"node123", InternalService:v1alpha3.GMCTarget{ServiceName:"", NameSpace:"", Config:map[string]string(nil), IsDownstreamService:false}, ExternalService:""}, Data:"", Condition:"", Dependency:"", ServiceURL:""}: node name: node123 in step Embedding does not exist
```

The nodename that is referenced within the `spec.nodes.<nodeName>.steps[].nodeName` field must already be defined in the `spec.nodes` section.

4. serviceName uniqueness

```
The GMCConnector "chatqa" is invalid: spec.nodes.root.steps[1].internalService.serviceName: Invalid value: v1alpha3.Step{StepName:"TeiEmbedding", Executor:v1alpha3.Executor{NodeName:"", InternalService:v1alpha3.GMCTarget{ServiceName:"tei-embedding-svc", NameSpace:"", Config:map[string]string(nil), IsDownstreamService:true}, ExternalService:""}, Data:"", Condition:"", Dependency:"", ServiceURL:""}: service name: tei-embedding-svc in node root already exists
```

The serviceName specified in the `spec.nodes.<nodeName>.steps[].internalService.serviceName` field must be unique and not duplicated with service names in other steps.

0 comments on commit b47ec0c

Please sign in to comment.