diff --git a/encoding/encoding.go b/encoding/encoding.go new file mode 100644 index 00000000..24fa378c --- /dev/null +++ b/encoding/encoding.go @@ -0,0 +1,51 @@ +package encoding + +import ( + "encoding/json" + + "gopkg.in/yaml.v2" +) + +// Unmarshal parses the JSON/YAML data and stores the result in the value pointed to by out +func Unmarshal(data []byte, out interface{}) error { + err := unmarshalJSON(data, out) + if err != nil { + err = unmarshalYAML(data, out) + if err != nil { + return err + } + } + return nil +} + +func unmarshalYAML(data []byte, result interface{}) error { + err := yaml.Unmarshal(data, result) + if err != nil { + return ErrDecodeYaml(err) + } + return nil +} + +func unmarshalJSON(data []byte, result interface{}) error { + + err := json.Unmarshal(data, result) + if err != nil { + if e, ok := err.(*json.SyntaxError); ok { + return ErrUnmarshalSyntax(err, e.Offset) + } + if e, ok := err.(*json.UnmarshalTypeError); ok { + return ErrUnmarshalType(err, e.Value) + } + if e, ok := err.(*json.UnsupportedTypeError); ok { + return ErrUnmarshalUnsupportedType(err, e.Type) + } + if e, ok := err.(*json.UnsupportedValueError); ok { + return ErrUnmarshalUnsupportedValue(err, e.Value) + } + if e, ok := err.(*json.InvalidUnmarshalError); ok { + return ErrUnmarshalInvalid(err, e.Type) + } + return ErrUnmarshal(err) + } + return nil +} diff --git a/encoding/error.go b/encoding/error.go new file mode 100644 index 00000000..7d100853 --- /dev/null +++ b/encoding/error.go @@ -0,0 +1,47 @@ +package encoding + +import ( + "reflect" + "strconv" + + "github.com/layer5io/meshkit/errors" +) + +const ( + ErrDecodeYamlCode = "" + ErrUnmarshalCode = "" + ErrUnmarshalInvalidCode = "" + ErrUnmarshalSyntaxCode = "" + ErrUnmarshalTypeCode = "" + ErrUnmarshalUnsupportedTypeCode = "" + ErrUnmarshalUnsupportedValueCode = "" +) + +// ErrDecodeYaml is the error when the yaml unmarshal fails +func ErrDecodeYaml(err error) error { + return errors.New(ErrDecodeYamlCode, errors.Alert, []string{"Error occurred while decoding YAML"}, []string{err.Error()}, []string{"Invalid object format"}, []string{"Make sure to input a valid YAML object"}) +} + +func ErrUnmarshal(err error) error { + return errors.New(ErrUnmarshalCode, errors.Alert, []string{"Unmarshal unknown error: "}, []string{err.Error()}, []string{"Invalid object format"}, []string{"Make sure to input a valid JSON object"}) +} + +func ErrUnmarshalInvalid(err error, typ reflect.Type) error { + return errors.New(ErrUnmarshalInvalidCode, errors.Alert, []string{"Unmarshal invalid error for type: ", typ.String()}, []string{err.Error()}, []string{"Invalid object format"}, []string{"Make sure to input a valid JSON object"}) +} + +func ErrUnmarshalSyntax(err error, offset int64) error { + return errors.New(ErrUnmarshalSyntaxCode, errors.Alert, []string{"Unmarshal syntax error at offest: ", strconv.Itoa(int(offset))}, []string{err.Error()}, []string{"Invalid object format"}, []string{"Make sure to input a valid JSON object"}) +} + +func ErrUnmarshalType(err error, value string) error { + return errors.New(ErrUnmarshalTypeCode, errors.Alert, []string{"Unmarshal type error at key: %s. Error: %s", value}, []string{err.Error()}, []string{"Invalid object format"}, []string{"Make sure to input a valid JSON object"}) +} + +func ErrUnmarshalUnsupportedType(err error, typ reflect.Type) error { + return errors.New(ErrUnmarshalUnsupportedTypeCode, errors.Alert, []string{"Unmarshal unsupported type error at key: ", typ.String()}, []string{err.Error()}, []string{"Invalid object format"}, []string{"Make sure to input a valid JSON object"}) +} + +func ErrUnmarshalUnsupportedValue(err error, value reflect.Value) error { + return errors.New(ErrUnmarshalUnsupportedValueCode, errors.Alert, []string{"Unmarshal unsupported value error at key: ", value.String()}, []string{err.Error()}, []string{"Invalid object format"}, []string{"Make sure to input a valid JSON object"}) +} diff --git a/generators/artifacthub/package.go b/generators/artifacthub/package.go index 4e1ef920..3c018813 100644 --- a/generators/artifacthub/package.go +++ b/generators/artifacthub/package.go @@ -10,8 +10,8 @@ import ( "github.com/layer5io/meshkit/utils" "github.com/layer5io/meshkit/utils/component" "github.com/layer5io/meshkit/utils/manifests" - _component "github.com/meshery/schemas/models/v1beta1/component" "github.com/meshery/schemas/models/v1beta1/category" + _component "github.com/meshery/schemas/models/v1beta1/component" "gopkg.in/yaml.v2" ) @@ -53,7 +53,7 @@ func (pkg AhPackage) GenerateComponents() ([]_component.ComponentDefinition, err if err != nil { continue } - + if comp.Model.Metadata.AdditionalProperties == nil { comp.Model.Metadata.AdditionalProperties = make(map[string]interface{}) } diff --git a/generators/models/interfaces.go b/generators/models/interfaces.go index 6aa0c808..19f61177 100644 --- a/generators/models/interfaces.go +++ b/generators/models/interfaces.go @@ -1,6 +1,6 @@ package models -import "github.com/meshery/schemas/models/v1beta1/component" +import "github.com/meshery/schemas/models/v1beta1/component" // anything that can be validated is a Validator type Validator interface { diff --git a/models/meshmodel/registry/error.go b/models/meshmodel/registry/error.go index 2566ec58..2e0351b4 100644 --- a/models/meshmodel/registry/error.go +++ b/models/meshmodel/registry/error.go @@ -14,18 +14,18 @@ var ( ErrRegisteringEntityCode = "replace_me" ErrUnknownHostInMapCode = "replace_me" ErrCreatingUserDataDirectoryCode = "replace_me" - ErrGetByIdCode = "replace_me" + ErrGetByIdCode = "replace_me" ) func ErrGetById(err error, id string) error { return errors.New( - ErrUnknownHostCode, - errors.Alert, - []string{"Failed to get the entity with the given ID: " + id}, - []string{err.Error()}, - []string{"Entity with the given ID may not be present in the registry", "Registry might be inaccessible at the moment"}, - []string{"Check if your ID is correct" , "If the registry is inaccesible, please try again after some time"}, - ) + ErrUnknownHostCode, + errors.Alert, + []string{"Failed to get the entity with the given ID: " + id}, + []string{err.Error()}, + []string{"Entity with the given ID may not be present in the registry", "Registry might be inaccessible at the moment"}, + []string{"Check if your ID is correct", "If the registry is inaccesible, please try again after some time"}, + ) } diff --git a/models/meshmodel/registry/registry.go b/models/meshmodel/registry/registry.go index 476a9055..91606a61 100644 --- a/models/meshmodel/registry/registry.go +++ b/models/meshmodel/registry/registry.go @@ -199,7 +199,7 @@ func (rm *RegistryManager) GetEntities(f entity.Filter) ([]entity.Entity, int64, return f.Get(rm.db) } -func (rm *RegistryManager) GetEntityById (f entity.Filter) (entity.Entity, error) { +func (rm *RegistryManager) GetEntityById(f entity.Filter) (entity.Entity, error) { return f.GetById(rm.db) } diff --git a/models/meshmodel/registry/v1beta1/policy_filter.go b/models/meshmodel/registry/v1beta1/policy_filter.go index 7de9ce07..d15d970c 100644 --- a/models/meshmodel/registry/v1beta1/policy_filter.go +++ b/models/meshmodel/registry/v1beta1/policy_filter.go @@ -8,7 +8,7 @@ import ( ) type PolicyFilter struct { - Id string + Id string Kind string Greedy bool SubType string @@ -26,12 +26,12 @@ func (pf *PolicyFilter) Create(m map[string]interface{}) { } func (pf *PolicyFilter) GetById(db *database.Handler) (entity.Entity, error) { - p := &v1beta1.PolicyDefinition{} - err := db.First(p, "id = ?", pf.Id).Error + p := &v1beta1.PolicyDefinition{} + err := db.First(p, "id = ?", pf.Id).Error if err != nil { return nil, registry.ErrGetById(err, pf.Id) } - return p, err + return p, err } func (pf *PolicyFilter) Get(db *database.Handler) ([]entity.Entity, int64, int, error) { diff --git a/models/registration/error.go b/models/registration/error.go index 73af3795..32e627c3 100644 --- a/models/registration/error.go +++ b/models/registration/error.go @@ -1,85 +1,83 @@ -package registration - -import ( - "fmt" - - "github.com/layer5io/meshkit/errors" -) - -const ( - ErrDirPkgUnitParseFailCode = "replace_me" - ErrGetEntityCode = "replace_me" - ErrRegisterEntityCode = "replace_me" - ErrImportFailureCode = "replace_me" - ErrMissingRegistrantCode = "replace_me" - ErrSeedingComponentsCode = "replace-me" -) - - - -func ErrSeedingComponents(err error) error { - return errors.New( - ErrSeedingComponentsCode, - errors.Alert, - []string{"Failed to register the given models into meshery's registry"}, - []string{err.Error()}, - []string{"Given models may not be in accordance with Meshery's schema", "Internal(OS level) error while reading files" }, - []string{"Make sure the models being seeded are valid in accordance with Meshery's schema", "If it is an internal error, please try again after some time"}, - ) -} - -func ErrMissingRegistrant(modelName string) error { - return errors.New( - ErrMissingRegistrantCode, - errors.Alert, - []string{fmt.Sprintf("Model with name: %s does not have registrant information", modelName)}, - []string{"Meshery models are always registered in context of a registrant."}, - // there is only one cause for this error - []string{""}, - []string{"Make sure that the registrant information is present in the model definition"}, - ) -} - -func ErrRegisterEntity(err error, name, entity string) error { - return errors.New( - ErrRegisterEntityCode, - errors.Alert, - []string{fmt.Sprintf("Failed to register an entity of name: %s and type: %s into Meshery's registry", name, entity)}, - []string{err.Error()}, - []string{fmt.Sprintf("%s definition might be violating the definition schema", entity), fmt.Sprintf("%s might be missing model details", entity)}, - []string{fmt.Sprintf("ensure the %s definition follows the correct schema", entity), fmt.Sprintf("ensure %s definition belongs to correct model", entity)}, - ) -} - -func ErrGetEntity(err error) error { - return errors.New( - ErrGetEntityCode, - errors.Alert, - []string{"Could not parse the given data into any Meshery entity"}, - []string{err.Error()}, - []string{"Entity definition might not be in accordance with it's corresponding schema", "Might be an invalid/unsupported schemaVersion"}, - []string{"Ensure that the definition given is in accordance with it's schema", "Ensure that the schemaVersion used is valid and is supported by Meshery"}, - ) -} - -func ErrDirPkgUnitParseFail(dirpath string, err error) error { - return errors.New( - ErrDirPkgUnitParseFailCode, - errors.Alert, - []string{fmt.Sprintf("Directory at path: %s cannot be registered into Meshery", dirpath)}, - []string{fmt.Sprint(err.Error())}, - []string{"The directory might not have a valid model definition", "Might be some internal issues while walking the file tree"}, - []string{"Make sure that there is a valid model definition present in the directory. Meshery's registration pipeline currently does not support nested models, therefore the behaviour might be unexpected if it contains nested models.", "If there is an internal error, please try again after some time"}, - ) -} - -func ErrImportFailure(hostname string, failedMsg string) error { - return errors.New( - ErrImportFailureCode, - errors.Alert, - []string{fmt.Sprintf("Errors while registering entities for registrant: %s", hostname)}, - []string{failedMsg}, - []string{"Entity definition might not be in accordance with schema", "Entity version might not be supported by Meshery"}, - []string{"See the registration logs (found at $HOME/.meshery/logs/registry/registry-logs.log) to find out which Entity failed to be imported with more specific error information."}, - ) -} \ No newline at end of file +package registration + +import ( + "fmt" + + "github.com/layer5io/meshkit/errors" +) + +const ( + ErrDirPkgUnitParseFailCode = "replace_me" + ErrGetEntityCode = "replace_me" + ErrRegisterEntityCode = "replace_me" + ErrImportFailureCode = "replace_me" + ErrMissingRegistrantCode = "replace_me" + ErrSeedingComponentsCode = "replace-me" +) + +func ErrSeedingComponents(err error) error { + return errors.New( + ErrSeedingComponentsCode, + errors.Alert, + []string{"Failed to register the given models into meshery's registry"}, + []string{err.Error()}, + []string{"Given models may not be in accordance with Meshery's schema", "Internal(OS level) error while reading files"}, + []string{"Make sure the models being seeded are valid in accordance with Meshery's schema", "If it is an internal error, please try again after some time"}, + ) +} + +func ErrMissingRegistrant(modelName string) error { + return errors.New( + ErrMissingRegistrantCode, + errors.Alert, + []string{fmt.Sprintf("Model with name: %s does not have registrant information", modelName)}, + []string{"Meshery models are always registered in context of a registrant."}, + // there is only one cause for this error + []string{""}, + []string{"Make sure that the registrant information is present in the model definition"}, + ) +} + +func ErrRegisterEntity(err error, name, entity string) error { + return errors.New( + ErrRegisterEntityCode, + errors.Alert, + []string{fmt.Sprintf("Failed to register an entity of name: %s and type: %s into Meshery's registry", name, entity)}, + []string{err.Error()}, + []string{fmt.Sprintf("%s definition might be violating the definition schema", entity), fmt.Sprintf("%s might be missing model details", entity)}, + []string{fmt.Sprintf("ensure the %s definition follows the correct schema", entity), fmt.Sprintf("ensure %s definition belongs to correct model", entity)}, + ) +} + +func ErrGetEntity(err error) error { + return errors.New( + ErrGetEntityCode, + errors.Alert, + []string{"Could not parse the given data into any Meshery entity"}, + []string{err.Error()}, + []string{"Entity definition might not be in accordance with it's corresponding schema", "Might be an invalid/unsupported schemaVersion"}, + []string{"Ensure that the definition given is in accordance with it's schema", "Ensure that the schemaVersion used is valid and is supported by Meshery"}, + ) +} + +func ErrDirPkgUnitParseFail(dirpath string, err error) error { + return errors.New( + ErrDirPkgUnitParseFailCode, + errors.Alert, + []string{fmt.Sprintf("Directory at path: %s cannot be registered into Meshery", dirpath)}, + []string{fmt.Sprint(err.Error())}, + []string{"The directory might not have a valid model definition", "Might be some internal issues while walking the file tree"}, + []string{"Make sure that there is a valid model definition present in the directory. Meshery's registration pipeline currently does not support nested models, therefore the behaviour might be unexpected if it contains nested models.", "If there is an internal error, please try again after some time"}, + ) +} + +func ErrImportFailure(hostname string, failedMsg string) error { + return errors.New( + ErrImportFailureCode, + errors.Alert, + []string{fmt.Sprintf("Errors while registering entities for registrant: %s", hostname)}, + []string{failedMsg}, + []string{"Entity definition might not be in accordance with schema", "Entity version might not be supported by Meshery"}, + []string{"See the registration logs (found at $HOME/.meshery/logs/registry/registry-logs.log) to find out which Entity failed to be imported with more specific error information."}, + ) +} diff --git a/models/registration/interface.go b/models/registration/interface.go index c13f1394..a8721a38 100644 --- a/models/registration/interface.go +++ b/models/registration/interface.go @@ -4,21 +4,19 @@ import ( "github.com/layer5io/meshkit/models/meshmodel/entity" ) -/* - RegistrationErrorStore stores all the errors that does not break the registration process, but have to be reported nevertheless. +/* + RegistrationErrorStore stores all the errors that does not break the registration process, but have to be reported nevertheless. */ type RegistrationErrorStore interface { - AddInvalidDefinition(string,error) - InsertEntityRegError(hostname string, modelName string, entityType entity.EntityType, entityName string, err error) + AddInvalidDefinition(string, error) + InsertEntityRegError(hostname string, modelName string, entityType entity.EntityType, entityName string, err error) } // Anything that can be parsed into a packagingUnit is a RegisterableEntity in Meshery server type RegisterableEntity interface { - /* - 1. `err` - this is a breaking error, which signifies that the given entity is invalid and cannot be registered + /* + 1. `err` - this is a breaking error, which signifies that the given entity is invalid and cannot be registered 2. Errors encountered while parsing items into meshmodel entites are stored in the RegistrationErrorStore */ PkgUnit(RegistrationErrorStore) (packagingUnit, error) } - - diff --git a/models/registration/oci.go b/models/registration/oci.go index 4aa42f50..8c8af21b 100644 --- a/models/registration/oci.go +++ b/models/registration/oci.go @@ -1,16 +1,14 @@ package registration - -import( +import ( gcrv1 "github.com/google/go-containerregistry/pkg/v1" - ) type OCIImage struct { - _ gcrv1.Image + _ gcrv1.Image } -func (o OCIImage) PkgUnit(regErrStore RegistrationErrorStore) (packagingUnit, error){ +func (o OCIImage) PkgUnit(regErrStore RegistrationErrorStore) (packagingUnit, error) { pkg := packagingUnit{} return pkg, nil } diff --git a/models/registration/register.go b/models/registration/register.go index b95e815e..d7b321b1 100644 --- a/models/registration/register.go +++ b/models/registration/register.go @@ -55,19 +55,26 @@ func (rh *RegistrationHelper) register(pkg packagingUnit) { rh.regErrStore.InsertEntityRegError(model.Registrant.Kind, "", entity.Model, model.Name, err) return } + if model.Metadata != nil { svgComplete := "" if model.Metadata.SvgComplete != nil { svgComplete = *model.Metadata.SvgComplete } + var svgCompletePath string + //Write SVG for models - WriteAndReplaceSVGWithFileSystemPath(model.Metadata.SvgColor, + model.Metadata.SvgColor, model.Metadata.SvgWhite, svgCompletePath = WriteAndReplaceSVGWithFileSystemPath(model.Metadata.SvgColor, model.Metadata.SvgWhite, svgComplete, rh.svgBaseDir, model.Name, model.Name, ) + if svgCompletePath != "" { + model.Metadata.SvgComplete = &svgCompletePath + } + } _, _, err := rh.regManager.RegisterEntity( connection.Connection{Kind: model.Registrant.Kind}, @@ -86,16 +93,19 @@ func (rh *RegistrationHelper) register(pkg packagingUnit) { // 2. Register components for _, comp := range pkg.components { comp.Model = model + if comp.Styles != nil { //Write SVG for components - WriteAndReplaceSVGWithFileSystemPath( + comp.Styles.SvgColor, comp.Styles.SvgWhite, comp.Styles.SvgComplete = WriteAndReplaceSVGWithFileSystemPath( comp.Styles.SvgColor, comp.Styles.SvgWhite, comp.Styles.SvgComplete, rh.svgBaseDir, comp.Model.Name, - comp.Component.Kind) //Write SVG on components + comp.Component.Kind, + ) } + _, _, err := rh.regManager.RegisterEntity( connection.Connection{Kind: model.Registrant.Kind}, &comp, diff --git a/models/registration/tar.go b/models/registration/tar.go index 66decb59..139a28bb 100644 --- a/models/registration/tar.go +++ b/models/registration/tar.go @@ -1,10 +1,10 @@ package registration type Tar struct { - _ string + _ string } -func (t Tar) PkgUnit(regErrStore RegistrationErrorStore) (packagingUnit, error){ +func (t Tar) PkgUnit(regErrStore RegistrationErrorStore) (packagingUnit, error) { pkg := packagingUnit{} return pkg, nil } diff --git a/models/registration/utils.go b/models/registration/utils.go index d3699fac..de8e1328 100644 --- a/models/registration/utils.go +++ b/models/registration/utils.go @@ -1,57 +1,45 @@ package registration import ( - "encoding/json" "fmt" + "github.com/layer5io/meshkit/encoding" "github.com/layer5io/meshkit/models/meshmodel/entity" "github.com/meshery/schemas/models/v1alpha3" "github.com/meshery/schemas/models/v1alpha3/relationship" "github.com/meshery/schemas/models/v1beta1" "github.com/meshery/schemas/models/v1beta1/component" "github.com/meshery/schemas/models/v1beta1/model" - "gopkg.in/yaml.v2" ) -func unmarshal(byt []byte, out interface{}) error { - err := json.Unmarshal(byt, out) - if err != nil { - err = yaml.Unmarshal(byt, out) - if err != nil { - return fmt.Errorf("Not a valid YAML or JSON") - } - } - return nil -} - // TODO: refactor this and use CUE func getEntity(byt []byte) (et entity.Entity, _ error) { type schemaVersion struct { SchemaVersion string `json:"schemaVersion" yaml:"schemaVersion"` } var sv schemaVersion - err := unmarshal(byt, &sv) + err := encoding.Unmarshal(byt, &sv) if err != nil || sv.SchemaVersion == "" { return nil, ErrGetEntity(fmt.Errorf("Does not contain versionmeta")) } switch sv.SchemaVersion { case v1beta1.ComponentSchemaVersion: var compDef component.ComponentDefinition - err := unmarshal(byt, &compDef) + err := encoding.Unmarshal(byt, &compDef) if err != nil { return nil, ErrGetEntity(fmt.Errorf("Invalid component definition: %s", err.Error())) } et = &compDef case v1beta1.ModelSchemaVersion: var model model.ModelDefinition - err := unmarshal(byt, &model) + err := encoding.Unmarshal(byt, &model) if err != nil { return nil, ErrGetEntity(fmt.Errorf("Invalid model definition: %s", err.Error())) } et = &model case v1alpha3.RelationshipSchemaVersion: var rel relationship.RelationshipDefinition - err := unmarshal(byt, &rel) + err := encoding.Unmarshal(byt, &rel) if err != nil { return nil, ErrGetEntity(fmt.Errorf("Invalid relationship definition: %s", err.Error())) } diff --git a/utils/utils.go b/utils/utils.go index 64d17c4e..73f1141f 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -38,7 +38,8 @@ func TransformMapKeys(input map[string]interface{}, transformFunc func(string) s return output } -// unmarshal returns parses the JSON config data and stores the value in the reference to result +// Deprecated: Use Unmarshal from encoding package. +// TODO: Replace the usages from all projects. func Unmarshal(obj string, result interface{}) error { obj = strings.TrimSpace(obj) err := json.Unmarshal([]byte(obj), result) @@ -408,7 +409,6 @@ func ExtractDomainFromURL(location string) string { } func IsInterfaceNil(val interface{}) bool { - fmt.Println("TEST 441 : ", val == nil) if val == nil { return true }