Files
Jian Zhu 7332a585c0 🌱 add a verify rule for golang files import order (#177)
* 🌱 add a verify rule for golang files import order

This PR uses the [gci tool](https://github.com/daixiang0/gci) to make all go files' import section with a specific order, it will organize import with group with order:
1. standard library modules
2. 3rd party modules
3. modules in OCM org, like the `open-cluster-management.io/api`
4. current project `open-cluster-management.io/ocm` modules

developers can use the `make fmt-imports` to format the import automatically and the `make verify-fmt-imports` to check for any violation.

Signed-off-by: zhujian <jiazhu@redhat.com>

* 🌱 format the go files import

Signed-off-by: zhujian <jiazhu@redhat.com>

---------

Signed-off-by: zhujian <jiazhu@redhat.com>
2023-06-12 10:23:04 -04:00

154 lines
4.1 KiB
Go

package statusfeedback
import (
"encoding/json"
"fmt"
"reflect"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/util/jsonpath"
"k8s.io/utils/pointer"
ocmfeature "open-cluster-management.io/api/feature"
workapiv1 "open-cluster-management.io/api/work/v1"
"open-cluster-management.io/ocm/pkg/features"
"open-cluster-management.io/ocm/pkg/work/spoke/statusfeedback/rules"
)
const maxJsonRawLength = 1024
type StatusReader struct {
wellKnownStatus rules.WellKnownStatusRuleResolver
}
func NewStatusReader() *StatusReader {
return &StatusReader{
wellKnownStatus: rules.DefaultWellKnownStatusRule(),
}
}
func (s *StatusReader) GetValuesByRule(obj *unstructured.Unstructured, rule workapiv1.FeedbackRule) ([]workapiv1.FeedbackValue, error) {
errs := []error{}
values := []workapiv1.FeedbackValue{}
switch rule.Type {
case workapiv1.WellKnownStatusType:
paths := s.wellKnownStatus.GetPathsByKind(obj.GroupVersionKind())
if len(paths) == 0 {
return values, fmt.Errorf("cannot find the wellknown statuses for resource with gvk %s", obj.GroupVersionKind().String())
}
for _, path := range paths {
value, err := getValueByJsonPath(path.Name, path.Path, obj)
if err != nil {
errs = append(errs, err)
continue
}
if value == nil {
continue
}
values = append(values, *value)
}
case workapiv1.JSONPathsType:
for _, path := range rule.JsonPaths {
// skip if version is specified and the object version does not match
if len(path.Version) != 0 && obj.GroupVersionKind().Version != path.Version {
errs = append(errs, fmt.Errorf("version set in the path %s is not matched for the related resource", path.Name))
continue
}
value, err := getValueByJsonPath(path.Name, path.Path, obj)
if err != nil {
errs = append(errs, err)
continue
}
if value == nil {
continue
}
values = append(values, *value)
}
}
return values, utilerrors.NewAggregate(errs)
}
func getValueByJsonPath(name, path string, obj *unstructured.Unstructured) (*workapiv1.FeedbackValue, error) {
j := jsonpath.New(name).AllowMissingKeys(true)
err := j.Parse(fmt.Sprintf("{%s}", path))
if err != nil {
return nil, fmt.Errorf("failed to parse json path %s of %s with error: %v", path, name, err)
}
results, err := j.FindResults(obj.UnstructuredContent())
if err != nil {
return nil, fmt.Errorf("failed to find value for %s with error: %v", name, err)
}
if len(results) == 0 || len(results[0]) == 0 {
// no results are found here.
return nil, nil
}
// as we only support simple JSON path, we can assume to have only one result (or none, filtered out above)
value := results[0][0].Interface()
if value == nil {
// ignore the result if it is nil
return nil, nil
}
var fieldValue workapiv1.FieldValue
switch t := value.(type) {
case int64:
fieldValue = workapiv1.FieldValue{
Type: workapiv1.Integer,
Integer: &t,
}
return &workapiv1.FeedbackValue{
Name: name,
Value: fieldValue,
}, nil
case string:
fieldValue = workapiv1.FieldValue{
Type: workapiv1.String,
String: &t,
}
return &workapiv1.FeedbackValue{
Name: name,
Value: fieldValue,
}, nil
case bool:
fieldValue = workapiv1.FieldValue{
Type: workapiv1.Boolean,
Boolean: &t,
}
return &workapiv1.FeedbackValue{
Name: name,
Value: fieldValue,
}, nil
default:
if features.DefaultSpokeWorkMutableFeatureGate.Enabled(ocmfeature.RawFeedbackJsonString) {
jsonRaw, err := json.Marshal(&t)
if err != nil {
return nil, fmt.Errorf("failed to parse the resource to json string for name %s: %v", name, err)
}
if len(jsonRaw) > maxJsonRawLength {
return nil, fmt.Errorf("the length of returned json raw string for name %s is larger than the maximum length %d", name, maxJsonRawLength)
}
fieldValue = workapiv1.FieldValue{
Type: workapiv1.JsonRaw,
JsonRaw: pointer.String(string(jsonRaw)),
}
return &workapiv1.FeedbackValue{
Name: name,
Value: fieldValue,
}, nil
}
}
return nil, fmt.Errorf("the type %v of the value for %s is not found", reflect.TypeOf(value), name)
}