From 7f881fabbe78cf70fc9f539290978a94359b91ad Mon Sep 17 00:00:00 2001 From: Jihoon Seo Date: Wed, 8 Sep 2021 18:28:27 +0900 Subject: [PATCH] Adopt struct validator more --- src/api/rest/docs/docs.go | 35 +++++ src/api/rest/docs/swagger.json | 35 +++++ src/api/rest/docs/swagger.yaml | 28 ++++ src/core/mcir/common.go | 8 +- src/core/mcir/image.go | 7 - src/core/mcir/securitygroup.go | 51 +++++++- src/core/mcir/spec.go | 49 ++++++- src/core/mcir/sshkey.go | 47 ++++++- src/core/mcir/vnet.go | 47 ++++++- src/core/mcis/control.go | 227 ++++++++++++++++++++++++++++++--- src/core/mcis/monitor.go | 24 ++++ src/core/mcis/utility.go | 33 +++++ 12 files changed, 545 insertions(+), 46 deletions(-) diff --git a/src/api/rest/docs/docs.go b/src/api/rest/docs/docs.go index b2c370c3a..4b7b13b3d 100644 --- a/src/api/rest/docs/docs.go +++ b/src/api/rest/docs/docs.go @@ -4916,6 +4916,12 @@ var doc = `{ }, "mcir.TbSecurityGroupReq": { "type": "object", + "required": [ + "connectionName", + "firewallRules", + "name", + "vNetId" + ], "properties": { "connectionName": { "type": "string" @@ -5053,6 +5059,11 @@ var doc = `{ }, "mcir.TbSpecReq": { "type": "object", + "required": [ + "connectionName", + "cspSpecName", + "name" + ], "properties": { "connectionName": { "type": "string" @@ -5120,6 +5131,10 @@ var doc = `{ }, "mcir.TbSshKeyReq": { "type": "object", + "required": [ + "connectionName", + "name" + ], "properties": { "connectionName": { "type": "string" @@ -5184,6 +5199,10 @@ var doc = `{ }, "mcir.TbVNetReq": { "type": "object", + "required": [ + "connectionName", + "name" + ], "properties": { "cidrBlock": { "type": "string" @@ -5392,6 +5411,9 @@ var doc = `{ }, "mcis.McisCmdReq": { "type": "object", + "required": [ + "command" + ], "properties": { "command": { "type": "string", @@ -5914,6 +5936,10 @@ var doc = `{ }, "mcis.TbMcisReq": { "type": "object", + "required": [ + "name", + "vm" + ], "properties": { "description": { "type": "string" @@ -6121,6 +6147,15 @@ var doc = `{ }, "mcis.TbVmReq": { "type": "object", + "required": [ + "connectionName", + "imageId", + "name", + "securityGroupIds", + "specId", + "sshKeyId", + "vNetId" + ], "properties": { "connectionName": { "type": "string" diff --git a/src/api/rest/docs/swagger.json b/src/api/rest/docs/swagger.json index fbeba5468..577aea012 100644 --- a/src/api/rest/docs/swagger.json +++ b/src/api/rest/docs/swagger.json @@ -4901,6 +4901,12 @@ }, "mcir.TbSecurityGroupReq": { "type": "object", + "required": [ + "connectionName", + "firewallRules", + "name", + "vNetId" + ], "properties": { "connectionName": { "type": "string" @@ -5038,6 +5044,11 @@ }, "mcir.TbSpecReq": { "type": "object", + "required": [ + "connectionName", + "cspSpecName", + "name" + ], "properties": { "connectionName": { "type": "string" @@ -5105,6 +5116,10 @@ }, "mcir.TbSshKeyReq": { "type": "object", + "required": [ + "connectionName", + "name" + ], "properties": { "connectionName": { "type": "string" @@ -5169,6 +5184,10 @@ }, "mcir.TbVNetReq": { "type": "object", + "required": [ + "connectionName", + "name" + ], "properties": { "cidrBlock": { "type": "string" @@ -5377,6 +5396,9 @@ }, "mcis.McisCmdReq": { "type": "object", + "required": [ + "command" + ], "properties": { "command": { "type": "string", @@ -5899,6 +5921,10 @@ }, "mcis.TbMcisReq": { "type": "object", + "required": [ + "name", + "vm" + ], "properties": { "description": { "type": "string" @@ -6106,6 +6132,15 @@ }, "mcis.TbVmReq": { "type": "object", + "required": [ + "connectionName", + "imageId", + "name", + "securityGroupIds", + "specId", + "sshKeyId", + "vNetId" + ], "properties": { "connectionName": { "type": "string" diff --git a/src/api/rest/docs/swagger.yaml b/src/api/rest/docs/swagger.yaml index 1316a37cf..cb2b6bae2 100644 --- a/src/api/rest/docs/swagger.yaml +++ b/src/api/rest/docs/swagger.yaml @@ -490,6 +490,11 @@ definitions: type: string vNetId: type: string + required: + - connectionName + - firewallRules + - name + - vNetId type: object mcir.TbSpecInfo: properties: @@ -577,6 +582,10 @@ definitions: type: string name: type: string + required: + - connectionName + - cspSpecName + - name type: object mcir.TbSshKeyInfo: properties: @@ -619,6 +628,9 @@ definitions: type: string name: type: string + required: + - connectionName + - name type: object mcir.TbVNetInfo: properties: @@ -667,6 +679,9 @@ definitions: items: $ref: '#/definitions/mcir.SpiderSubnetReqInfo' type: array + required: + - connectionName + - name type: object mcis.AgentInstallContent: properties: @@ -800,6 +815,8 @@ definitions: userName: example: cb-user type: string + required: + - command type: object mcis.McisPolicyInfo: properties: @@ -1181,6 +1198,9 @@ definitions: items: $ref: '#/definitions/mcis.TbVmReq' type: array + required: + - name + - vm type: object mcis.TbVmInfo: properties: @@ -1333,6 +1353,14 @@ definitions: type: string vmUserPassword: type: string + required: + - connectionName + - imageId + - name + - securityGroupIds + - specId + - sshKeyId + - vNetId type: object mcis.TbVmStatusInfo: properties: diff --git a/src/core/mcir/common.go b/src/core/mcir/common.go index 3cd7a62ca..f36add07d 100644 --- a/src/core/mcir/common.go +++ b/src/core/mcir/common.go @@ -47,10 +47,14 @@ func init() { return name }) - // register validation for 'TbImageReq' - // NOTE: only have to register a non-pointer type for 'TbImageReq', validator + // register validation for 'Tb*Req' + // NOTE: only have to register a non-pointer type for 'Tb*Req', validator // internally dereferences during it's type checks. validate.RegisterStructValidation(TbImageReqStructLevelValidation, TbImageReq{}) + validate.RegisterStructValidation(TbSecurityGroupReqStructLevelValidation, TbSecurityGroupReq{}) + validate.RegisterStructValidation(TbSpecReqStructLevelValidation, TbSpecReq{}) + validate.RegisterStructValidation(TbSshKeyReqStructLevelValidation, TbSshKeyReq{}) + validate.RegisterStructValidation(TbVNetReqStructLevelValidation, TbVNetReq{}) } // DelAllResources deletes all TB MCIR object of given resourceType diff --git a/src/core/mcir/image.go b/src/core/mcir/image.go index fcc576a16..3937e8f64 100644 --- a/src/core/mcir/image.go +++ b/src/core/mcir/image.go @@ -117,13 +117,6 @@ func RegisterImageWithId(nsId string, u *TbImageReq) (TbImageInfo, error) { return temp, err } - // err = common.CheckString(u.Name) - // if err != nil { - // temp := TbImageInfo{} - // common.CBLog.Error(err) - // return temp, err - // } - // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) err = validate.Struct(u) if err != nil { diff --git a/src/core/mcir/securitygroup.go b/src/core/mcir/securitygroup.go index 766e795d9..4b83e539f 100644 --- a/src/core/mcir/securitygroup.go +++ b/src/core/mcir/securitygroup.go @@ -8,6 +8,7 @@ import ( "github.com/cloud-barista/cb-spider/interface/api" "github.com/cloud-barista/cb-tumblebug/src/core/common" + validator "github.com/go-playground/validator/v10" "github.com/go-resty/resty/v2" ) @@ -51,11 +52,22 @@ type SpiderSecurityInfo struct { // Spider } type TbSecurityGroupReq struct { // Tumblebug - Name string `json:"name"` - ConnectionName string `json:"connectionName"` - VNetId string `json:"vNetId"` + Name string `json:"name" validate:"required"` + ConnectionName string `json:"connectionName" validate:"required"` + VNetId string `json:"vNetId" validate:"required"` Description string `json:"description"` - FirewallRules *[]SpiderSecurityRuleInfo `json:"firewallRules"` + FirewallRules *[]SpiderSecurityRuleInfo `json:"firewallRules" validate:"required"` +} + +func TbSecurityGroupReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(TbSecurityGroupReq) + + err := common.CheckString(u.Name) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.Name, "name", "Name", "NotObeyingNamingConvention", "") + } } type TbSecurityGroupInfo struct { // Tumblebug @@ -86,12 +98,39 @@ func CreateSecurityGroup(nsId string, u *TbSecurityGroupReq) (TbSecurityGroupInf common.CBLog.Error(err) return temp, err } - err = common.CheckString(u.Name) + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(u) if err != nil { + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + temp := TbSecurityGroupInfo{} + return temp, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + temp := TbSecurityGroupInfo{} - common.CBLog.Error(err) return temp, err } + check, err := CheckResource(nsId, resourceType, u.Name) if check { diff --git a/src/core/mcir/spec.go b/src/core/mcir/spec.go index 2bc64a520..7bbbb54e8 100644 --- a/src/core/mcir/spec.go +++ b/src/core/mcir/spec.go @@ -12,6 +12,7 @@ import ( "github.com/cloud-barista/cb-spider/interface/api" "github.com/cloud-barista/cb-tumblebug/src/core/common" + validator "github.com/go-playground/validator/v10" "github.com/go-resty/resty/v2" //"github.com/cloud-barista/cb-tumblebug/src/core/mcis" @@ -44,12 +45,23 @@ type SpiderGpuInfo struct { // Spider } type TbSpecReq struct { // Tumblebug - Name string `json:"name"` - ConnectionName string `json:"connectionName"` - CspSpecName string `json:"cspSpecName"` + Name string `json:"name" validate:"required"` + ConnectionName string `json:"connectionName" validate:"required"` + CspSpecName string `json:"cspSpecName" validate:"required"` Description string `json:"description"` } +func TbSpecReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(TbSpecReq) + + err := common.CheckString(u.Name) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.Name, "name", "Name", "NotObeyingNamingConvention", "") + } +} + type TbSpecInfo struct { // Tumblebug Namespace string `json:"namespace"` // required to save in RDB Id string `json:"id"` @@ -367,12 +379,39 @@ func RegisterSpecWithCspSpecName(nsId string, u *TbSpecReq) (TbSpecInfo, error) common.CBLog.Error(err) return temp, err } - err = common.CheckString(u.Name) + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(u) if err != nil { + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + temp := TbSpecInfo{} + return temp, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + temp := TbSpecInfo{} - common.CBLog.Error(err) return temp, err } + check, _ := CheckResource(nsId, resourceType, u.Name) if check { diff --git a/src/core/mcir/sshkey.go b/src/core/mcir/sshkey.go index b42b25980..a55226218 100644 --- a/src/core/mcir/sshkey.go +++ b/src/core/mcir/sshkey.go @@ -8,6 +8,7 @@ import ( "github.com/cloud-barista/cb-spider/interface/api" "github.com/cloud-barista/cb-tumblebug/src/core/common" + validator "github.com/go-playground/validator/v10" "github.com/go-resty/resty/v2" ) @@ -38,11 +39,22 @@ type SpiderKeyPairInfo struct { // Spider } type TbSshKeyReq struct { - Name string `json:"name"` - ConnectionName string `json:"connectionName"` + Name string `json:"name" validate:"required"` + ConnectionName string `json:"connectionName" validate:"required"` Description string `json:"description"` } +func TbSshKeyReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(TbSshKeyReq) + + err := common.CheckString(u.Name) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.Name, "name", "Name", "NotObeyingNamingConvention", "") + } +} + type TbSshKeyInfo struct { Id string `json:"id"` Name string `json:"name"` @@ -70,12 +82,39 @@ func CreateSshKey(nsId string, u *TbSshKeyReq) (TbSshKeyInfo, error) { common.CBLog.Error(err) return temp, err } - err = common.CheckString(u.Name) + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(u) if err != nil { + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + temp := TbSshKeyInfo{} + return temp, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + temp := TbSshKeyInfo{} - common.CBLog.Error(err) return temp, err } + check, err := CheckResource(nsId, resourceType, u.Name) if check { diff --git a/src/core/mcir/vnet.go b/src/core/mcir/vnet.go index d05e2489b..4168f4bf8 100644 --- a/src/core/mcir/vnet.go +++ b/src/core/mcir/vnet.go @@ -8,6 +8,7 @@ import ( "github.com/cloud-barista/cb-spider/interface/api" "github.com/cloud-barista/cb-tumblebug/src/core/common" + validator "github.com/go-playground/validator/v10" "github.com/go-resty/resty/v2" ) @@ -45,13 +46,24 @@ type SpiderSubnetInfo struct { // Spider } type TbVNetReq struct { // Tumblebug - Name string `json:"name"` - ConnectionName string `json:"connectionName"` + Name string `json:"name" validate:"required"` + ConnectionName string `json:"connectionName" validate:"required"` CidrBlock string `json:"cidrBlock"` SubnetInfoList []SpiderSubnetReqInfo `json:"subnetInfoList"` Description string `json:"description"` } +func TbVNetReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(TbVNetReq) + + err := common.CheckString(u.Name) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.Name, "name", "Name", "NotObeyingNamingConvention", "") + } +} + type TbVNetInfo struct { // Tumblebug Id string `json:"id"` Name string `json:"name"` @@ -82,12 +94,39 @@ func CreateVNet(nsId string, u *TbVNetReq) (TbVNetInfo, error) { common.CBLog.Error(err) return temp, err } - err = common.CheckString(u.Name) + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(u) if err != nil { + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + temp := TbVNetInfo{} + return temp, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + temp := TbVNetInfo{} - common.CBLog.Error(err) return temp, err } + check, err := CheckResource(nsId, resourceType, u.Name) if check { diff --git a/src/core/mcis/control.go b/src/core/mcis/control.go index 1b37971c0..cc9dc3f66 100644 --- a/src/core/mcis/control.go +++ b/src/core/mcis/control.go @@ -28,6 +28,7 @@ import ( "github.com/cloud-barista/cb-spider/interface/api" "github.com/cloud-barista/cb-tumblebug/src/core/common" "github.com/cloud-barista/cb-tumblebug/src/core/mcir" + validator "github.com/go-playground/validator/v10" cbstore_utils "github.com/cloud-barista/cb-store/utils" ) @@ -145,7 +146,7 @@ type RegionInfo struct { // Spider } type TbMcisReq struct { - Name string `json:"name"` + Name string `json:"name" validate:"required"` // InstallMonAgent Option for CB-Dragonfly agent installation ([yes/no] default:yes) InstallMonAgent string `json:"installMonAgent" example:"yes" default:"yes" enums:"yes,no"` // yes or no @@ -156,7 +157,18 @@ type TbMcisReq struct { PlacementAlgo string `json:"placementAlgo"` Description string `json:"description"` - Vm []TbVmReq `json:"vm"` + Vm []TbVmReq `json:"vm" validate:"required"` +} + +func TbMcisReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(TbMcisReq) + + err := common.CheckString(u.Name) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.Name, "name", "Name", "NotObeyingNamingConvention", "") + } } type TbMcisInfo struct { @@ -180,7 +192,7 @@ type TbMcisInfo struct { // struct TbVmReq is to get requirements to create a new server instance. type TbVmReq struct { // VM name or VM group name if is (not empty) && (> 0). If it is a group, actual VM name will be generated with -N postfix. - Name string `json:"name"` + Name string `json:"name" validate:"required"` // if vmGroupSize is (not empty) && (> 0), VM group will be gernetad. VMs will be created accordingly. VmGroupSize string `json:"vmGroupSize" example:"3" default:""` @@ -189,17 +201,28 @@ type TbVmReq struct { Description string `json:"description"` - ConnectionName string `json:"connectionName"` - SpecId string `json:"specId"` - ImageId string `json:"imageId"` - VNetId string `json:"vNetId"` + ConnectionName string `json:"connectionName" validate:"required"` + SpecId string `json:"specId" validate:"required"` + ImageId string `json:"imageId" validate:"required"` + VNetId string `json:"vNetId" validate:"required"` SubnetId string `json:"subnetId"` - SecurityGroupIds []string `json:"securityGroupIds"` - SshKeyId string `json:"sshKeyId"` + SecurityGroupIds []string `json:"securityGroupIds" validate:"required"` + SshKeyId string `json:"sshKeyId" validate:"required"` VmUserAccount string `json:"vmUserAccount"` VmUserPassword string `json:"vmUserPassword"` } +func TbVmReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(TbVmReq) + + err := common.CheckString(u.Name) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.Name, "name", "Name", "NotObeyingNamingConvention", "") + } +} + // struct TbVmGroupInfo is to define an object that includes homogeneous VMs. type TbVmGroupInfo struct { Id string `json:"id"` @@ -314,7 +337,18 @@ type TbVmStatusInfo struct { // McisCmdReq is remote command struct type McisCmdReq struct { UserName string `json:"userName" example:"cb-user" default:""` - Command string `json:"command" example:"sudo apt-get install ..." default:""` + Command string `json:"command" validate:"required" example:"sudo apt-get install ..."` +} + +func TbMcisCmdReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(McisCmdReq) + + err := common.CheckString(u.Command) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.Command, "command", "Command", "NotObeyingNamingConvention", "") + } } type McisRecommendReq struct { @@ -1850,6 +1884,37 @@ func CorePostCmdMcisVm(nsId string, mcisId string, vmId string, req *McisCmdReq) common.CBLog.Error(err) return "", err } + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(req) + if err != nil { + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + return "", err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + + return "", err + } + check, _ := CheckVm(nsId, mcisId, vmId) if !check { @@ -1899,6 +1964,39 @@ func CorePostCmdMcis(nsId string, mcisId string, req *McisCmdReq) ([]SshCmdResul common.CBLog.Error(err) return nil, err } + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(req) + if err != nil { + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + temp := []SshCmdResult{} + return temp, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + + temp := []SshCmdResult{} + return temp, err + } + check, _ := CheckMcis(nsId, mcisId) if !check { @@ -2065,6 +2163,50 @@ func CorePostMcisVm(nsId string, mcisId string, vmInfoData *TbVmInfo) (*TbVmInfo // CorePostMcisGroupVm function is a wrapper for CreateMcisGroupVm func CorePostMcisGroupVm(nsId string, mcisId string, vmReq *TbVmReq) (*TbMcisInfo, error) { + err := common.CheckString(nsId) + if err != nil { + temp := &TbMcisInfo{} + common.CBLog.Error(err) + return temp, err + } + + err = common.CheckString(mcisId) + if err != nil { + temp := &TbMcisInfo{} + common.CBLog.Error(err) + return temp, err + } + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(vmReq) + if err != nil { + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + return nil, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + + return nil, err + } + content, err := CreateMcisGroupVm(nsId, mcisId, vmReq) if err != nil { common.CBLog.Error(err) @@ -2088,11 +2230,35 @@ func CreateMcisGroupVm(nsId string, mcisId string, vmRequest *TbVmReq) (*TbMcisI common.CBLog.Error(err) return temp, err } - err = common.CheckString(vmRequest.Name) + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(vmRequest) if err != nil { - temp := &TbMcisInfo{} - common.CBLog.Error(err) - return temp, err + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + return nil, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + + return nil, err } mcisTmp, err := GetMcisObject(nsId, mcisId) @@ -2422,12 +2588,37 @@ func CreateMcis(nsId string, req *TbMcisReq) (*TbMcisInfo, error) { common.CBLog.Error(err) return temp, err } - err = common.CheckString(req.Name) + + // returns InvalidValidationError for bad validation input, nil or ValidationErrors ( []FieldError ) + err = validate.Struct(req) if err != nil { - temp := &TbMcisInfo{} - common.CBLog.Error(err) - return temp, err + + // this check is only needed when your code could produce + // an invalid value for validation such as interface with nil + // value most including myself do not usually have code like this. + if _, ok := err.(*validator.InvalidValidationError); ok { + fmt.Println(err) + return nil, err + } + + // for _, err := range err.(validator.ValidationErrors) { + + // fmt.Println(err.Namespace()) // can differ when a custom TagNameFunc is registered or + // fmt.Println(err.Field()) // by passing alt name to ReportError like below + // fmt.Println(err.StructNamespace()) + // fmt.Println(err.StructField()) + // fmt.Println(err.Tag()) + // fmt.Println(err.ActualTag()) + // fmt.Println(err.Kind()) + // fmt.Println(err.Type()) + // fmt.Println(err.Value()) + // fmt.Println(err.Param()) + // fmt.Println() + // } + + return nil, err } + check, _ := CheckMcis(nsId, req.Name) if check { err := fmt.Errorf("The mcis " + req.Name + " already exists.") diff --git a/src/core/mcis/monitor.go b/src/core/mcis/monitor.go index 8dd9e6aa4..81049109c 100644 --- a/src/core/mcis/monitor.go +++ b/src/core/mcis/monitor.go @@ -7,6 +7,7 @@ import ( "os" "time" + validator "github.com/go-playground/validator/v10" "github.com/tidwall/gjson" "fmt" @@ -54,6 +55,29 @@ type MonAgentInstallReq struct { CspType string `json:"cspType,omitempty"` } +func DFMonAgentInstallReqStructLevelValidation(sl validator.StructLevel) { + + u := sl.Current().Interface().(MonAgentInstallReq) + + err := common.CheckString(u.NsId) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.NsId, "nsId", "NsId", "NotObeyingNamingConvention", "") + } + + err = common.CheckString(u.McisId) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.McisId, "mcisId", "McisId", "NotObeyingNamingConvention", "") + } + + err = common.CheckString(u.VmId) + if err != nil { + // ReportError(field interface{}, fieldName, structFieldName, tag, param string) + sl.ReportError(u.VmId, "vmId", "VmId", "NotObeyingNamingConvention", "") + } +} + /* type DfTelegrafMetric struct { Name string `json:"name"` diff --git a/src/core/mcis/utility.go b/src/core/mcis/utility.go index 45b679fb1..21a1c298c 100644 --- a/src/core/mcis/utility.go +++ b/src/core/mcis/utility.go @@ -21,6 +21,10 @@ import ( //"github.com/cloud-barista/cb-tumblebug/src/core/common" "github.com/go-resty/resty/v2" + + "reflect" + + validator "github.com/go-playground/validator/v10" ) // CB-Store @@ -29,10 +33,39 @@ import ( //var SPIDER_REST_URL string +// use a single instance of Validate, it caches struct info +var validate *validator.Validate + func init() { //cblog = config.Cblogger //store = cbstore.GetStore() //SPIDER_REST_URL = os.Getenv("SPIDER_REST_URL") + + validate = validator.New() + + // register function to get tag name from json tags. + validate.RegisterTagNameFunc(func(fld reflect.StructField) string { + name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] + if name == "-" { + return "" + } + return name + }) + + // register validation for 'Tb*Req' + // NOTE: only have to register a non-pointer type for 'Tb*Req', validator + // internally dereferences during it's type checks. + + validate.RegisterStructValidation(TbMcisReqStructLevelValidation, TbMcisReq{}) + validate.RegisterStructValidation(TbVmReqStructLevelValidation, TbVmReq{}) + validate.RegisterStructValidation(TbMcisCmdReqStructLevelValidation, McisCmdReq{}) + // validate.RegisterStructValidation(TbMcisRecommendReqStructLevelValidation, McisRecommendReq{}) + // validate.RegisterStructValidation(TbVmRecommendReqStructLevelValidation, TbVmRecommendReq{}) + // validate.RegisterStructValidation(TbBenchmarkReqStructLevelValidation, BenchmarkReq{}) + // validate.RegisterStructValidation(TbMultihostBenchmarkReqStructLevelValidation, MultihostBenchmarkReq{}) + + validate.RegisterStructValidation(DFMonAgentInstallReqStructLevelValidation, MonAgentInstallReq{}) + } /*