You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by ra...@apache.org on 2022/05/18 20:09:54 UTC
[trafficcontrol] branch master updated: Remove tc.DBError, make api.Validators return two errors (#6770)
This is an automated email from the ASF dual-hosted git repository.
rawlin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new f4c3f770ba Remove tc.DBError, make api.Validators return two errors (#6770)
f4c3f770ba is described below
commit f4c3f770ba45c2a4fc1d05e9bace3ec39799380e
Author: ocket8888 <oc...@apache.org>
AuthorDate: Wed May 18 14:09:49 2022 -0600
Remove tc.DBError, make api.Validators return two errors (#6770)
---
lib/go-tc/constants.go | 5 --
lib/go-tc/steeringtarget.go | 6 +-
.../traffic_ops_golang/api/shared_handlers.go | 40 ++++++----
.../traffic_ops_golang/api/shared_handlers_test.go | 6 +-
.../traffic_ops_golang/api/shared_interfaces.go | 9 ++-
traffic_ops/traffic_ops_golang/apitenant/tenant.go | 6 +-
traffic_ops/traffic_ops_golang/asn/asns.go | 4 +-
traffic_ops/traffic_ops_golang/asn/asns_test.go | 3 +-
.../traffic_ops_golang/cachegroup/cachegroups.go | 33 ++++----
.../cachegroup/cachegroups_test.go | 10 ++-
traffic_ops/traffic_ops_golang/cdn/cdns.go | 6 +-
traffic_ops/traffic_ops_golang/cdn/cdns_test.go | 5 +-
.../cdnfederation/cdnfederations.go | 12 +--
.../traffic_ops_golang/coordinate/coordinates.go | 6 +-
.../coordinate/coordinates_test.go | 5 +-
.../deliveryservice/deliveryservices.go | 3 +-
.../deliveryservices_required_capabilities.go | 12 +--
.../deliveryservice/request/comment/comments.go | 6 +-
.../request/comment/comments_test.go | 5 +-
.../traffic_ops_golang/division/divisions.go | 4 +-
.../traffic_ops_golang/division/divisions_test.go | 3 +-
traffic_ops/traffic_ops_golang/origin/origins.go | 7 +-
.../traffic_ops_golang/origin/origins_test.go | 8 +-
.../traffic_ops_golang/parameter/parameters.go | 4 +-
.../physlocation/phys_locations.go | 6 +-
.../physlocation/phys_locations_test.go | 4 +-
traffic_ops/traffic_ops_golang/profile/profiles.go | 6 +-
.../traffic_ops_golang/profile/profiles_test.go | 5 +-
.../profileparameter/profile_parameters.go | 6 +-
traffic_ops/traffic_ops_golang/region/regions.go | 8 +-
.../traffic_ops_golang/region/regions_test.go | 6 +-
traffic_ops/traffic_ops_golang/role/roles.go | 7 +-
traffic_ops/traffic_ops_golang/role/roles_test.go | 12 ++-
traffic_ops/traffic_ops_golang/server/servers.go | 89 +++++++++++++---------
.../server/servers_assignment.go | 3 +-
.../server/servers_server_capability.go | 8 +-
.../traffic_ops_golang/server/servers_test.go | 18 ++---
.../server/servers_update_status.go | 16 ++--
.../server/servers_update_status_test.go | 2 +-
.../servercapability/servercapability.go | 4 +-
.../servicecategory/servicecategories.go | 14 ++--
.../staticdnsentry/staticdnsentry.go | 8 +-
.../staticdnsentry/staticdnsentry_test.go | 3 +-
traffic_ops/traffic_ops_golang/status/statuses.go | 4 +-
.../steeringtargets/steeringtargets.go | 2 +-
.../steeringtargets/steeringtargets_test.go | 5 +-
.../traffic_ops_golang/topology/topologies.go | 26 ++-----
traffic_ops/traffic_ops_golang/types/types.go | 6 +-
traffic_ops/traffic_ops_golang/types/types_test.go | 3 +-
traffic_ops/traffic_ops_golang/user/user.go | 8 +-
50 files changed, 264 insertions(+), 223 deletions(-)
diff --git a/lib/go-tc/constants.go b/lib/go-tc/constants.go
index 3ccfb66967..188d604bed 100644
--- a/lib/go-tc/constants.go
+++ b/lib/go-tc/constants.go
@@ -34,11 +34,6 @@ type ErrorConstant string
// Error converts ErrorConstants to a string.
func (e ErrorConstant) Error() string { return string(e) }
-// DBError is an error message for database errors.
-//
-// Deprecated: Since internal errors are not returned to users, there's no reason not to include more detail in an error message than this.
-const DBError = ErrorConstant("database access error")
-
// NilTenantError can used when a Tenantable object finds that TentantID in the
// request is nil.
const NilTenantError = ErrorConstant("tenancy is enabled but request tenantID is nil")
diff --git a/lib/go-tc/steeringtarget.go b/lib/go-tc/steeringtarget.go
index 8dc13676bd..dbc836225b 100644
--- a/lib/go-tc/steeringtarget.go
+++ b/lib/go-tc/steeringtarget.go
@@ -58,7 +58,7 @@ type SteeringTargetNullable struct {
// Validate implements the
// github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api.ParseValidator
// interface.
-func (st SteeringTargetNullable) Validate(tx *sql.Tx) error {
+func (st SteeringTargetNullable) Validate(tx *sql.Tx) (error, error) {
errs := []string{}
if st.TypeID == nil {
errs = append(errs, "missing typeId")
@@ -71,9 +71,9 @@ func (st SteeringTargetNullable) Validate(tx *sql.Tx) error {
errs = append(errs, "missing value")
}
if len(errs) > 0 {
- return errors.New(strings.Join(errs, "; "))
+ return errors.New(strings.Join(errs, "; ")), nil
}
- return nil
+ return nil, nil
}
// SteeringTargetsResponse is the type of a response from Traffic Ops to its
diff --git a/traffic_ops/traffic_ops_golang/api/shared_handlers.go b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
index a657b27f29..2e86dff6eb 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_handlers.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_handlers.go
@@ -103,11 +103,11 @@ func GetCombinedParams(r *http.Request) (map[string]string, error) {
}
// decodeAndValidateRequestBody decodes and validates a pointer to a struct implementing the Validator interface
-func decodeAndValidateRequestBody(r *http.Request, v Validator) error {
+func decodeAndValidateRequestBody(r *http.Request, v Validator) (error, error) {
defer r.Body.Close()
if err := json.NewDecoder(r.Body).Decode(v); err != nil {
- return err
+ return err, nil
}
return v.Validate()
}
@@ -242,8 +242,12 @@ func UpdateHandler(updater Updater) http.HandlerFunc {
obj := reflect.New(objectType).Interface().(Updater)
obj.SetInfo(inf)
- if err := decodeAndValidateRequestBody(r, obj); err != nil {
- HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, err, nil)
+ if userErr, sysErr := decodeAndValidateRequestBody(r, obj); userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ HandleErr(w, r, inf.Tx.Tx, code, userErr, sysErr)
return
}
@@ -298,7 +302,7 @@ func UpdateHandler(updater Updater) http.HandlerFunc {
}
if err := CreateChangeLog(ApiChange, Updated, obj, inf.User, inf.Tx.Tx); err != nil {
- HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, tc.DBError, errors.New("inserting changelog: "+err.Error()))
+ HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("inserting changelog: %w", err))
return
}
alerts := tc.CreateAlerts(tc.SuccessLevel, obj.GetType()+" was updated.")
@@ -489,9 +493,13 @@ func CreateHandler(creator Creator) http.HandlerFunc {
for _, objElemInt := range objSlice {
objElem := reflect.ValueOf(objElemInt).Interface().(Creator)
- err = objElem.Validate()
- if err != nil {
- HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, err, nil)
+ userErr, sysErr = objElem.Validate()
+ if userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ HandleErr(w, r, inf.Tx.Tx, code, userErr, sysErr)
return
}
@@ -514,7 +522,7 @@ func CreateHandler(creator Creator) http.HandlerFunc {
}
if err = CreateChangeLog(ApiChange, Created, objElem, inf.User, inf.Tx.Tx); err != nil {
- HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, tc.DBError, errors.New("inserting changelog: "+err.Error()))
+ HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("inserting changelog: %w", err))
return
}
}
@@ -541,9 +549,13 @@ func CreateHandler(creator Creator) http.HandlerFunc {
WriteAlertsObj(w, r, http.StatusOK, alerts, responseObj)
} else {
- err := decodeAndValidateRequestBody(r, obj)
- if err != nil {
- HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, err, nil)
+ userErr, sysErr := decodeAndValidateRequestBody(r, obj)
+ if userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ HandleErr(w, r, inf.Tx.Tx, code, userErr, sysErr)
return
}
@@ -565,8 +577,8 @@ func CreateHandler(creator Creator) http.HandlerFunc {
return
}
- if err = CreateChangeLog(ApiChange, Created, obj, inf.User, inf.Tx.Tx); err != nil {
- HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, tc.DBError, errors.New("inserting changelog: "+err.Error()))
+ if err := CreateChangeLog(ApiChange, Created, obj, inf.User, inf.Tx.Tx); err != nil {
+ HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("inserting changelog: %w", err))
return
}
alerts := tc.CreateAlerts(tc.SuccessLevel, obj.GetType()+" was created.")
diff --git a/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go b/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go
index 2a26e18f38..51675ee5b2 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_handlers_test.go
@@ -72,11 +72,11 @@ func (i *tester) GetAuditName() string {
}
//Validator interface function
-func (v *tester) Validate() error {
+func (v *tester) Validate() (error, error) {
if v.ID < 1 {
- return errors.New("ID is too low")
+ return errors.New("ID is too low"), nil
}
- return nil
+ return nil, nil
}
//Creator interface functions
diff --git a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
index d9e46fab95..1d92773935 100644
--- a/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
+++ b/traffic_ops/traffic_ops_golang/api/shared_interfaces.go
@@ -20,11 +20,12 @@ package api
*/
import (
+ "net/http"
+ "time"
+
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
- "net/http"
- "time"
)
type CRUDer interface {
@@ -103,8 +104,10 @@ type OptionsDeleter interface {
DeleteKeyOptions() map[string]dbhelpers.WhereColumnInfo
}
+// Validator objects return user and system errors based on validation rules
+// defined by that object.
type Validator interface {
- Validate() error
+ Validate() (error, error)
}
type Tenantable interface {
diff --git a/traffic_ops/traffic_ops_golang/apitenant/tenant.go b/traffic_ops/traffic_ops_golang/apitenant/tenant.go
index 49c1d75584..929656490a 100644
--- a/traffic_ops/traffic_ops_golang/apitenant/tenant.go
+++ b/traffic_ops/traffic_ops_golang/apitenant/tenant.go
@@ -121,15 +121,15 @@ func (ten *TOTenant) SetKeys(keys map[string]interface{}) {
ten.ID = &i
}
-// Validate fulfills the api.Validator interface
-func (ten TOTenant) Validate() error {
+// Validate fulfills the api.Validator interface.
+func (ten TOTenant) Validate() (error, error) {
errs := validation.Errors{
"name": validation.Validate(ten.Name, validation.Required),
"active": validation.Validate(ten.Active), // only validate it's boolean
"parentId": validation.Validate(ten.ParentID, validation.Required, validation.Min(1)),
"parentName": nil,
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (ten *TOTenant) Create() (error, error, int) { return api.GenericCreate(ten) }
diff --git a/traffic_ops/traffic_ops_golang/asn/asns.go b/traffic_ops/traffic_ops_golang/asn/asns.go
index 3e96117321..2c7ec6a871 100644
--- a/traffic_ops/traffic_ops_golang/asn/asns.go
+++ b/traffic_ops/traffic_ops_golang/asn/asns.go
@@ -95,12 +95,12 @@ func (asn TOASNV11) GetType() string {
return "asn"
}
-func (asn TOASNV11) Validate() error {
+func (asn TOASNV11) Validate() (error, error) {
errs := validation.Errors{
"asn": validation.Validate(asn.ASN, validation.NotNil, validation.Min(0)),
"cachegroupId": validation.Validate(asn.CachegroupID, validation.NotNil, validation.Min(0)),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (as *TOASNV11) Create() (error, error, int) {
diff --git a/traffic_ops/traffic_ops_golang/asn/asns_test.go b/traffic_ops/traffic_ops_golang/asn/asns_test.go
index 67410c50f0..62a46af7f8 100644
--- a/traffic_ops/traffic_ops_golang/asn/asns_test.go
+++ b/traffic_ops/traffic_ops_golang/asn/asns_test.go
@@ -125,7 +125,8 @@ func TestValidate(t *testing.T) {
api.APIInfoImpl{},
tc.ASNNullable{ASN: &i, CachegroupID: &i},
}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(asn.Validate())))
+ err, _ := asn.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expected := util.JoinErrsStr([]error{
errors.New(`'asn' must be no less than 0`),
errors.New(`'cachegroupId' must be no less than 0`),
diff --git a/traffic_ops/traffic_ops_golang/cachegroup/cachegroups.go b/traffic_ops/traffic_ops_golang/cachegroup/cachegroups.go
index 155934635b..46355e8fc3 100644
--- a/traffic_ops/traffic_ops_golang/cachegroup/cachegroups.go
+++ b/traffic_ops/traffic_ops_golang/cachegroup/cachegroups.go
@@ -247,28 +247,31 @@ func (cg *TOCacheGroup) ValidateTypeInTopology() error {
return fmt.Errorf("cannot change type of cachegroup %s from %s to %s because it is in use by a topology", *cg.Name, typeNameByID[previousTypeID], typeNameByID[*cg.TypeID])
}
-// Validate fulfills the api.Validator interface
-func (cg TOCacheGroup) Validate() error {
+// Validate fulfills the api.Validator interface.
+//
+// TODO: A lot of database operations here either swallow their errors or return
+// them to the client.
+func (cg TOCacheGroup) Validate() (error, error) {
if _, err := tc.ValidateTypeID(cg.ReqInfo.Tx.Tx, cg.TypeID, "cachegroup"); err != nil {
- return err
+ return err, nil
}
if cg.Fallbacks != nil && len(*cg.Fallbacks) > 0 {
isValid, err := cg.isAllowedToFallback(*cg.TypeID)
if err != nil {
- return err
+ return err, nil
}
if !isValid {
- return errors.New("the cache group " + *cg.Name + " is not allowed to have fallbacks. It must be of type EDGE_LOC.")
+ return errors.New("the cache group " + *cg.Name + " is not allowed to have fallbacks. It must be of type EDGE_LOC."), nil
}
for _, fallback := range *cg.Fallbacks {
isValid, err = cg.isValidCacheGroupFallback(fallback)
if err != nil {
- return err
+ return err, nil
}
if !isValid {
- return errors.New("the cache group " + fallback + " is not valid as a fallback. It must exist as a cache group and be of type EDGE_LOC.")
+ return errors.New("the cache group " + fallback + " is not valid as a fallback. It must exist as a cache group and be of type EDGE_LOC."), nil
}
}
}
@@ -287,7 +290,7 @@ func (cg TOCacheGroup) Validate() error {
"localizationMethods": validation.Validate(cg.LocalizationMethods, validation.By(tovalidate.IsPtrToSliceOfUniqueStringersICase("CZ", "DEEP_CZ", "GEO"))),
"type": cg.ValidateTypeInTopology(),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
//The TOCacheGroup implementation of the Creator interface
@@ -393,10 +396,10 @@ func (cg *TOCacheGroup) createCacheGroupFallbacks() error {
func (cg *TOCacheGroup) isValidCacheGroupFallback(fallbackName string) (bool, error) {
var isValid bool
query := `SELECT(
-SELECT cachegroup.id
-FROM cachegroup
-JOIN type on type.id = cachegroup.type
-WHERE cachegroup.name = $1
+SELECT cachegroup.id
+FROM cachegroup
+JOIN type on type.id = cachegroup.type
+WHERE cachegroup.name = $1
AND (type.name = 'EDGE_LOC')
) IS NOT NULL;`
@@ -411,9 +414,9 @@ AND (type.name = 'EDGE_LOC')
func (cg *TOCacheGroup) isAllowedToFallback(cacheGroupType int) (bool, error) {
var isValid bool
query := `SELECT(
-SELECT type.name
-FROM type
-WHERE type.id = $1
+SELECT type.name
+FROM type
+WHERE type.id = $1
AND (type.name = 'EDGE_LOC')
) IS NOT NULL;`
diff --git a/traffic_ops/traffic_ops_golang/cachegroup/cachegroups_test.go b/traffic_ops/traffic_ops_golang/cachegroup/cachegroups_test.go
index ae3c701102..601f05af1a 100644
--- a/traffic_ops/traffic_ops_golang/cachegroup/cachegroups_test.go
+++ b/traffic_ops/traffic_ops_golang/cachegroup/cachegroups_test.go
@@ -231,7 +231,8 @@ func TestValidate(t *testing.T) {
LastUpdated: &lu,
},
}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(c.Validate())))
+ err, _ = c.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expectedErrs := util.JoinErrsStr([]error{
errors.New(`'latitude' Must be a floating point number within the range +-90`),
@@ -272,9 +273,12 @@ func TestValidate(t *testing.T) {
LastUpdated: &lu,
},
}
- err = c.Validate()
+ err, sysErr := c.Validate()
if err != nil {
- t.Errorf("expected nil, got %s", err)
+ t.Errorf("expected nil user error, got: %s", err)
+ }
+ if sysErr != nil {
+ t.Errorf("expected nil system error, got: %s", sysErr)
}
}
diff --git a/traffic_ops/traffic_ops_golang/cdn/cdns.go b/traffic_ops/traffic_ops_golang/cdn/cdns.go
index 79ccdd01a2..e98a4b92a0 100644
--- a/traffic_ops/traffic_ops_golang/cdn/cdns.go
+++ b/traffic_ops/traffic_ops_golang/cdn/cdns.go
@@ -120,15 +120,15 @@ func IsValidCDNName(str string) bool {
return i == -1
}
-// Validate fulfills the api.Validator interface
-func (cdn TOCDN) Validate() error {
+// Validate fulfills the api.Validator interface.
+func (cdn TOCDN) Validate() (error, error) {
validName := validation.NewStringRule(IsValidCDNName, "invalid characters found - Use alphanumeric . or - .")
validDomainName := validation.NewStringRule(govalidator.IsDNSName, "not a valid domain name")
errs := validation.Errors{
"name": validation.Validate(cdn.Name, validation.Required, validName),
"domainName": validation.Validate(cdn.DomainName, validation.Required, validDomainName),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (cdn *TOCDN) Create() (error, error, int) {
diff --git a/traffic_ops/traffic_ops_golang/cdn/cdns_test.go b/traffic_ops/traffic_ops_golang/cdn/cdns_test.go
index 7830f550e8..baa10197c3 100644
--- a/traffic_ops/traffic_ops_golang/cdn/cdns_test.go
+++ b/traffic_ops/traffic_ops_golang/cdn/cdns_test.go
@@ -136,7 +136,8 @@ func TestValidate(t *testing.T) {
// invalid name, empty domainname
n := "not_a_valid_cdn"
c := TOCDN{CDNNullable: tc.CDNNullable{Name: &n}}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(c.Validate())))
+ err, _ := c.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expectedErrs := util.JoinErrsStr([]error{
errors.New(`'domainName' cannot be blank`),
@@ -151,7 +152,7 @@ func TestValidate(t *testing.T) {
n = "This.is.2.a-Valid---CDNNAME."
d := `awesome-cdn.example.net`
c = TOCDN{CDNNullable: tc.CDNNullable{Name: &n, DomainName: &d}}
- err := c.Validate()
+ err, _ = c.Validate()
if err != nil {
t.Errorf("expected nil, got %s", err)
}
diff --git a/traffic_ops/traffic_ops_golang/cdnfederation/cdnfederations.go b/traffic_ops/traffic_ops_golang/cdnfederation/cdnfederations.go
index 54a218e290..b15b61283b 100644
--- a/traffic_ops/traffic_ops_golang/cdnfederation/cdnfederations.go
+++ b/traffic_ops/traffic_ops_golang/cdnfederation/cdnfederations.go
@@ -35,7 +35,7 @@ import (
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
"github.com/asaskevich/govalidator"
- "github.com/go-ozzo/ozzo-validation"
+ validation "github.com/go-ozzo/ozzo-validation"
)
// we need a type alias to define functions on
@@ -53,9 +53,9 @@ func (v *TOCDNFederation) SetLastUpdated(t tc.TimeNoMod) { v.LastUpdated = &t }
func (v *TOCDNFederation) InsertQuery() string { return insertQuery() }
func (v *TOCDNFederation) SelectMaxLastUpdatedQuery(where, orderBy, pagination, tableName string) string {
return `SELECT max(t) from (
- SELECT max(federation.last_updated) as t from federation
- join federation_deliveryservice fds on fds.federation = federation.id
- join deliveryservice ds on ds.id = fds.deliveryservice
+ SELECT max(federation.last_updated) as t from federation
+ join federation_deliveryservice fds on fds.federation = federation.id
+ join deliveryservice ds on ds.id = fds.deliveryservice
join cdn c on c.id = ds.cdn_id ` + where + orderBy + pagination +
` UNION ALL
select max(last_updated) as t from last_deleted l where l.table_name='federation') as res`
@@ -112,7 +112,7 @@ func (fed *TOCDNFederation) SetKeys(keys map[string]interface{}) {
}
// Fulfills `Validate' interface
-func (fed *TOCDNFederation) Validate() error {
+func (fed *TOCDNFederation) Validate() (error, error) {
isDNSName := validation.NewStringRule(govalidator.IsDNSName, "must be a valid hostname")
endsWithDot := validation.NewStringRule(
@@ -125,7 +125,7 @@ func (fed *TOCDNFederation) Validate() error {
"cname": validation.Validate(fed.CName, validation.Required, endsWithDot, isDNSName),
"ttl": validation.Validate(fed.TTL, validation.Required, validation.Min(0)),
}
- return util.JoinErrs(tovalidate.ToErrors(validateErrs))
+ return util.JoinErrs(tovalidate.ToErrors(validateErrs)), nil
}
func (fed *TOCDNFederation) CheckIfCDNAndFederationMatch(cdnName string) (error, error, int) {
diff --git a/traffic_ops/traffic_ops_golang/coordinate/coordinates.go b/traffic_ops/traffic_ops_golang/coordinate/coordinates.go
index 51d19fc10a..29b40589b8 100644
--- a/traffic_ops/traffic_ops_golang/coordinate/coordinates.go
+++ b/traffic_ops/traffic_ops_golang/coordinate/coordinates.go
@@ -110,8 +110,8 @@ func IsValidCoordinateName(str string) bool {
return i == -1
}
-// Validate fulfills the api.Validator interface
-func (coordinate TOCoordinate) Validate() error {
+// Validate fulfills the api.Validator interface.
+func (coordinate TOCoordinate) Validate() (error, error) {
validName := validation.NewStringRule(IsValidCoordinateName, "invalid characters found - Use alphanumeric . or - or _ .")
latitudeErr := "Must be a floating point number within the range +-90"
longitudeErr := "Must be a floating point number within the range +-180"
@@ -120,7 +120,7 @@ func (coordinate TOCoordinate) Validate() error {
"latitude": validation.Validate(coordinate.Latitude, validation.Min(-90.0).Error(latitudeErr), validation.Max(90.0).Error(latitudeErr)),
"longitude": validation.Validate(coordinate.Longitude, validation.Min(-180.0).Error(longitudeErr), validation.Max(180.0).Error(longitudeErr)),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (coord *TOCoordinate) Create() (error, error, int) { return api.GenericCreate(coord) }
diff --git a/traffic_ops/traffic_ops_golang/coordinate/coordinates_test.go b/traffic_ops/traffic_ops_golang/coordinate/coordinates_test.go
index 330af9c637..0fa8bb5971 100644
--- a/traffic_ops/traffic_ops_golang/coordinate/coordinates_test.go
+++ b/traffic_ops/traffic_ops_golang/coordinate/coordinates_test.go
@@ -148,7 +148,8 @@ func TestValidate(t *testing.T) {
Longitude: &lo,
LastUpdated: &lu,
}}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(c.Validate())))
+ err, _ := c.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expectedErrs := util.JoinErrsStr([]error{
errors.New(`'latitude' Must be a floating point number within the range +-90`),
@@ -170,7 +171,7 @@ func TestValidate(t *testing.T) {
Longitude: &lo,
LastUpdated: &lu,
}}
- err := c.Validate()
+ err, _ = c.Validate()
if err != nil {
t.Errorf("expected nil, got %s", err)
}
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go
index 5f045c56d9..3966186eeb 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go
@@ -1284,8 +1284,7 @@ func readGetDeliveryServices(h http.Header, params map[string]string, tx *sqlx.T
accessibleTo, _ := strconv.Atoi(accessibleTo)
accessibleTenants, err := tenant.GetUserTenantIDListTx(tx.Tx, accessibleTo)
if err != nil {
- log.Errorln("unable to get tenants: " + err.Error())
- return nil, nil, tc.DBError, http.StatusInternalServerError, &maxTime
+ return nil, nil, fmt.Errorf("unable to get tenants: %w", err), http.StatusInternalServerError, &maxTime
}
where += " AND ds.tenant_id = ANY(CAST(:accessibleTo AS bigint[])) "
queryValues["accessibleTo"] = pq.Array(accessibleTenants)
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go
index 043495132e..b6b75b3dd8 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices_required_capabilities.go
@@ -155,13 +155,13 @@ func (rc *RequiredCapability) GetType() string {
}
// Validate implements the api.Validator interface.
-func (rc RequiredCapability) Validate() error {
+func (rc RequiredCapability) Validate() (error, error) {
errs := validation.Errors{
deliveryServiceQueryParam: validation.Validate(rc.DeliveryServiceID, validation.Required),
requiredCapabilityQueryParam: validation.Validate(rc.RequiredCapability, validation.Required),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
// Update implements the api.CRUDer interface.
@@ -344,8 +344,8 @@ func (rc *RequiredCapability) checkServerCap() (error, error, int) {
// Get server capability name
name := ""
if err := tx.QueryRow(`
- SELECT name
- FROM server_capability
+ SELECT name
+ FROM server_capability
WHERE name = $1`, rc.RequiredCapability).Scan(&name); err != nil && err != sql.ErrNoRows {
return nil, fmt.Errorf("querying server capability for name '%v': %v", rc.RequiredCapability, err), http.StatusInternalServerError
}
@@ -436,7 +436,7 @@ func (rc *RequiredCapability) ensureDSServerCap() (error, error, int) {
dsServerIDs := []int64{}
if err := tx.Tx.QueryRow(`
SELECT ARRAY(
- SELECT ds.server
+ SELECT ds.server
FROM deliveryservice_server ds
JOIN server s ON ds.server = s.id
JOIN type t ON s.type = t.id
@@ -455,7 +455,7 @@ func (rc *RequiredCapability) ensureDSServerCap() (error, error, int) {
if err := tx.QueryRow(`
SELECT ARRAY(
SELECT server
- FROM server_server_capability
+ FROM server_server_capability
WHERE server = ANY($1)
AND server_capability=$2
)`, pq.Array(dsServerIDs), rc.RequiredCapability).Scan(pq.Array(&capServerIDs)); err != nil && err != sql.ErrNoRows {
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments.go
index b58a027f7e..3c08d1c92d 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments.go
@@ -31,7 +31,7 @@ import (
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
- "github.com/go-ozzo/ozzo-validation"
+ validation "github.com/go-ozzo/ozzo-validation"
)
//we need a type alias to define functions on
@@ -98,12 +98,12 @@ func (comment TODeliveryServiceRequestComment) GetType() string {
return "deliveryservice_request_comment"
}
-func (comment TODeliveryServiceRequestComment) Validate() error {
+func (comment TODeliveryServiceRequestComment) Validate() (error, error) {
errs := validation.Errors{
"deliveryServiceRequestId": validation.Validate(comment.DeliveryServiceRequestID, validation.NotNil),
"value": validation.Validate(comment.Value, validation.NotNil),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (comment *TODeliveryServiceRequestComment) Create() (error, error, int) {
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments_test.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments_test.go
index b16ac6c8bc..de7f41b531 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments_test.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/comment/comments_test.go
@@ -69,7 +69,8 @@ func TestInterfaces(t *testing.T) {
func TestValidate(t *testing.T) {
c := TODeliveryServiceRequestComment{}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(c.Validate())))
+ err, _ := c.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expectedErrs := util.JoinErrsStr([]error{
errors.New(`'deliveryServiceRequestId' is required`),
@@ -84,7 +85,7 @@ func TestValidate(t *testing.T) {
d := 1
c = TODeliveryServiceRequestComment{DeliveryServiceRequestCommentNullable: tc.DeliveryServiceRequestCommentNullable{DeliveryServiceRequestID: &d, Value: &v}}
- err := c.Validate()
+ err, _ = c.Validate()
if err != nil {
t.Errorf("expected nil, got %s", err)
}
diff --git a/traffic_ops/traffic_ops_golang/division/divisions.go b/traffic_ops/traffic_ops_golang/division/divisions.go
index 7bcf4b03f0..57d45cc92d 100644
--- a/traffic_ops/traffic_ops_golang/division/divisions.go
+++ b/traffic_ops/traffic_ops_golang/division/divisions.go
@@ -95,11 +95,11 @@ func (division TODivision) GetType() string {
return "division"
}
-func (division TODivision) Validate() error {
+func (division TODivision) Validate() (error, error) {
errs := validation.Errors{
"name": validation.Validate(division.Name, validation.NotNil, validation.Required),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (dv *TODivision) Create() (error, error, int) { return api.GenericCreate(dv) }
diff --git a/traffic_ops/traffic_ops_golang/division/divisions_test.go b/traffic_ops/traffic_ops_golang/division/divisions_test.go
index 4f7b050fd4..1e683510cc 100644
--- a/traffic_ops/traffic_ops_golang/division/divisions_test.go
+++ b/traffic_ops/traffic_ops_golang/division/divisions_test.go
@@ -111,7 +111,8 @@ func TestInterfaces(t *testing.T) {
func TestValidation(t *testing.T) {
div := TODivision{}
- errs := test.SortErrors(test.SplitErrors(div.Validate()))
+ err, _ := div.Validate()
+ errs := test.SortErrors(test.SplitErrors(err))
expected := []error{}
if reflect.DeepEqual(expected, errs) {
diff --git a/traffic_ops/traffic_ops_golang/origin/origins.go b/traffic_ops/traffic_ops_golang/origin/origins.go
index bfb1523762..de94740dc1 100644
--- a/traffic_ops/traffic_ops_golang/origin/origins.go
+++ b/traffic_ops/traffic_ops_golang/origin/origins.go
@@ -84,7 +84,7 @@ func (origin *TOOrigin) GetType() string {
return "origin"
}
-func (origin *TOOrigin) Validate() error {
+func (origin *TOOrigin) Validate() (error, error) {
noSpaces := validation.NewStringRule(tovalidate.NoSpaces, "cannot contain spaces")
validProtocol := validation.NewStringRule(tovalidate.IsOneOfStringICase("http", "https"), "must be http or https")
@@ -103,7 +103,7 @@ func (origin *TOOrigin) Validate() error {
"protocol": validation.Validate(origin.Protocol, validation.Required, validProtocol),
"tenantId": validation.Validate(origin.TenantID, validation.Min(1)),
}
- return util.JoinErrs(tovalidate.ToErrors(validateErrs))
+ return util.JoinErrs(tovalidate.ToErrors(validateErrs)), nil
}
// GetTenantID returns a pointer to the Origin's tenant ID from the Tx, whether or not the Origin exists, and any error encountered
@@ -182,8 +182,7 @@ func getOrigins(h http.Header, params map[string]string, tx *sqlx.Tx, user *auth
tenantIDs, err := tenant.GetUserTenantIDListTx(tx.Tx, user.TenantID)
if err != nil {
- log.Errorln("received error querying for user's tenants: " + err.Error())
- return nil, nil, tc.DBError, http.StatusInternalServerError, nil
+ return nil, nil, fmt.Errorf("received error querying for user's tenants: %w", err), http.StatusInternalServerError, nil
}
where, queryValues = dbhelpers.AddTenancyCheck(where, queryValues, "o.tenant", tenantIDs)
diff --git a/traffic_ops/traffic_ops_golang/origin/origins_test.go b/traffic_ops/traffic_ops_golang/origin/origins_test.go
index f072527ca9..a4e1220ab8 100644
--- a/traffic_ops/traffic_ops_golang/origin/origins_test.go
+++ b/traffic_ops/traffic_ops_golang/origin/origins_test.go
@@ -186,7 +186,8 @@ func TestValidate(t *testing.T) {
FQDN: nil,
Protocol: nil,
}}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(c.Validate())))
+ err, _ := c.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expectedErrs := util.JoinErrsStr([]error{
errors.New(`'deliveryServiceId' is required`),
@@ -218,7 +219,7 @@ func TestValidate(t *testing.T) {
Protocol: &pro,
LastUpdated: &lu,
}}
- err := c.Validate()
+ err, _ = c.Validate()
if err != nil {
t.Errorf("expected nil, got %s", err)
}
@@ -323,7 +324,8 @@ func TestValidate(t *testing.T) {
c.IP6Address = &tc.Str
value = tc.Str
}
- errStr := util.JoinErrsStr(test.SortErrors(test.SplitErrors(c.Validate())))
+ err, _ = c.Validate()
+ errStr := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
if !reflect.DeepEqual(util.JoinErrsStr(tc.ExpectedErrors), errStr) {
t.Errorf("given: '%v', expected %s, got %s", value, tc.ExpectedErrors, errStr)
}
diff --git a/traffic_ops/traffic_ops_golang/parameter/parameters.go b/traffic_ops/traffic_ops_golang/parameter/parameters.go
index d1ccc4e3e8..8d719fa3d3 100644
--- a/traffic_ops/traffic_ops_golang/parameter/parameters.go
+++ b/traffic_ops/traffic_ops_golang/parameter/parameters.go
@@ -119,7 +119,7 @@ func (param *TOParameter) GetType() string {
}
// Validate fulfills the api.Validator interface
-func (param TOParameter) Validate() error {
+func (param TOParameter) Validate() (error, error) {
// Test
// - Secure Flag is always set to either 1/0
// - Admin rights only
@@ -133,7 +133,7 @@ func (param TOParameter) Validate() error {
errs[atscfg.ParentConfigFileName+" "+atscfg.ParentConfigCacheParamWeight] = validation.Validate(*param.Value, tovalidate.StringIsValidFloat())
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (pa *TOParameter) Create() (error, error, int) {
diff --git a/traffic_ops/traffic_ops_golang/physlocation/phys_locations.go b/traffic_ops/traffic_ops_golang/physlocation/phys_locations.go
index d6fbd85907..51b31c455e 100644
--- a/traffic_ops/traffic_ops_golang/physlocation/phys_locations.go
+++ b/traffic_ops/traffic_ops_golang/physlocation/phys_locations.go
@@ -90,7 +90,7 @@ func (pl *TOPhysLocation) GetType() string {
return "physLocation"
}
-func (pl *TOPhysLocation) Validate() error {
+func (pl *TOPhysLocation) Validate() (error, error) {
errs := validation.Errors{
"address": validation.Validate(pl.Address, validation.Required),
"city": validation.Validate(pl.City, validation.Required),
@@ -101,9 +101,9 @@ func (pl *TOPhysLocation) Validate() error {
"zip": validation.Validate(pl.Zip, validation.Required),
}
if errs != nil {
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
- return nil
+ return nil, nil
}
func (pl *TOPhysLocation) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
diff --git a/traffic_ops/traffic_ops_golang/physlocation/phys_locations_test.go b/traffic_ops/traffic_ops_golang/physlocation/phys_locations_test.go
index 67d0eb99cd..727183f453 100644
--- a/traffic_ops/traffic_ops_golang/physlocation/phys_locations_test.go
+++ b/traffic_ops/traffic_ops_golang/physlocation/phys_locations_test.go
@@ -134,8 +134,8 @@ func TestInterfaces(t *testing.T) {
}
func TestValidate(t *testing.T) {
- p := TOPhysLocation{}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(p.Validate())))
+ err, _ := (&TOPhysLocation{}).Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expected := util.JoinErrsStr(test.SortErrors([]error{
errors.New("'state' cannot be blank"),
errors.New("'zip' cannot be blank"),
diff --git a/traffic_ops/traffic_ops_golang/profile/profiles.go b/traffic_ops/traffic_ops_golang/profile/profiles.go
index 4ae0e8ae48..2305e8b8af 100644
--- a/traffic_ops/traffic_ops_golang/profile/profiles.go
+++ b/traffic_ops/traffic_ops_golang/profile/profiles.go
@@ -102,7 +102,7 @@ func (prof *TOProfile) GetType() string {
return "profile"
}
-func (prof *TOProfile) Validate() error {
+func (prof *TOProfile) Validate() (error, error) {
errs := validation.Errors{
NameQueryParam: validation.Validate(prof.Name, validation.By(
func(value interface{}) error {
@@ -124,9 +124,9 @@ func (prof *TOProfile) Validate() error {
TypeQueryParam: validation.Validate(prof.Type, validation.Required),
}
if errs != nil {
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
- return nil
+ return nil, nil
}
func (prof *TOProfile) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
diff --git a/traffic_ops/traffic_ops_golang/profile/profiles_test.go b/traffic_ops/traffic_ops_golang/profile/profiles_test.go
index 26a98dc4c9..ebd6e86944 100644
--- a/traffic_ops/traffic_ops_golang/profile/profiles_test.go
+++ b/traffic_ops/traffic_ops_golang/profile/profiles_test.go
@@ -138,7 +138,8 @@ func TestInterfaces(t *testing.T) {
func TestValidate(t *testing.T) {
p := TOProfile{}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(p.Validate())))
+ err, _ := p.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expected := util.JoinErrsStr(test.SortErrors([]error{
errors.New("'cdn' cannot be blank"),
errors.New("'description' cannot be blank"),
@@ -159,7 +160,7 @@ func TestValidate(t *testing.T) {
p.Type = new(string)
*p.Type = "type"
- err := p.Validate()
+ err, _ = p.Validate()
if !strings.Contains(err.Error(), "cannot contain spaces") {
t.Error("Expected an error about the Profile name containing spaces")
}
diff --git a/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters.go b/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters.go
index 0065660309..b66e4379dd 100644
--- a/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters.go
+++ b/traffic_ops/traffic_ops_golang/profileparameter/profile_parameters.go
@@ -98,15 +98,15 @@ func (pp *TOProfileParameter) SetKeys(keys map[string]interface{}) {
pp.ParameterID = ¶mId
}
-// Validate fulfills the api.Validator interface
-func (pp *TOProfileParameter) Validate() error {
+// Validate fulfills the api.Validator interface.
+func (pp *TOProfileParameter) Validate() (error, error) {
errs := validation.Errors{
"profileId": validation.Validate(pp.ProfileID, validation.Required),
"parameterId": validation.Validate(pp.ParameterID, validation.Required),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
//The TOProfileParameter implementation of the Creator interface
diff --git a/traffic_ops/traffic_ops_golang/region/regions.go b/traffic_ops/traffic_ops_golang/region/regions.go
index 27a180722e..9263059fbd 100644
--- a/traffic_ops/traffic_ops_golang/region/regions.go
+++ b/traffic_ops/traffic_ops_golang/region/regions.go
@@ -94,14 +94,14 @@ func (region *TORegion) GetType() string {
return "region"
}
-func (region *TORegion) Validate() error {
+func (region *TORegion) Validate() (error, error) {
if len(region.Name) < 1 {
- return errors.New(`region 'name' is required`)
+ return errors.New(`region 'name' is required`), nil
}
if region.Division == 0 {
- return errors.New(`region 'division' is required`)
+ return errors.New(`region 'division' is required`), nil
}
- return nil
+ return nil, nil
}
func (rg *TORegion) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
diff --git a/traffic_ops/traffic_ops_golang/region/regions_test.go b/traffic_ops/traffic_ops_golang/region/regions_test.go
index 27ea29f4f6..d34d337e2d 100644
--- a/traffic_ops/traffic_ops_golang/region/regions_test.go
+++ b/traffic_ops/traffic_ops_golang/region/regions_test.go
@@ -118,7 +118,8 @@ func TestValidation(t *testing.T) {
LastUpdated: tc.TimeNoMod{Time: time.Now()},
}
testTORegion := TORegion{Region: testRegion}
- errs := test.SortErrors(test.SplitErrors(testTORegion.Validate()))
+ err, _ := testTORegion.Validate()
+ errs := test.SortErrors(test.SplitErrors(err))
if len(errs) > 0 {
t.Errorf(`expected no errors, got %v`, errs)
@@ -130,7 +131,8 @@ func TestValidation(t *testing.T) {
LastUpdated: tc.TimeNoMod{Time: time.Now()},
}
testTORegionNoDivision := TORegion{Region: testRegionNoDivision}
- errs = test.SortErrors(test.SplitErrors(testTORegionNoDivision.Validate()))
+ err, _ = testTORegionNoDivision.Validate()
+ errs = test.SortErrors(test.SplitErrors(err))
if len(errs) == 0 {
t.Errorf(`expected an error with a nil division id, received no error`)
} else {
diff --git a/traffic_ops/traffic_ops_golang/role/roles.go b/traffic_ops/traffic_ops_golang/role/roles.go
index 623958eb1a..43878e53b2 100644
--- a/traffic_ops/traffic_ops_golang/role/roles.go
+++ b/traffic_ops/traffic_ops_golang/role/roles.go
@@ -129,7 +129,7 @@ func (role *TORole) SetKeys(keys map[string]interface{}) {
}
// Validate fulfills the api.Validator interface
-func (role TORole) Validate() error {
+func (role TORole) Validate() (error, error) {
errs := validation.Errors{
"name": validation.Validate(role.Name, validation.Required),
"description": validation.Validate(role.Description, validation.Required),
@@ -141,14 +141,13 @@ func (role TORole) Validate() error {
if role.ReqInfo.Tx != nil {
err := role.ReqInfo.Tx.Select(&badCaps, checkCaps, pq.Array(role.Capabilities))
if err != nil {
- log.Errorf("got error from selecting bad capabilities: %v", err)
- return tc.DBError
+ return nil, fmt.Errorf("got error from selecting bad capabilities: %w", err)
}
if len(badCaps) > 0 {
errsToReturn = append(errsToReturn, fmt.Errorf("can not add non-existent capabilities: %v", badCaps))
}
}
- return util.JoinErrs(errsToReturn)
+ return util.JoinErrs(errsToReturn), nil
}
func (role *TORole) Create() (error, error, int) {
diff --git a/traffic_ops/traffic_ops_golang/role/roles_test.go b/traffic_ops/traffic_ops_golang/role/roles_test.go
index bc6b508c6a..4d65a421cf 100644
--- a/traffic_ops/traffic_ops_golang/role/roles_test.go
+++ b/traffic_ops/traffic_ops_golang/role/roles_test.go
@@ -86,7 +86,8 @@ func TestValidate(t *testing.T) {
APIInfoImpl: api.APIInfoImpl{ReqInfo: &reqInfo},
Role: role,
}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(r.Validate())))
+ userErr, _ := r.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(userErr)))
expectedErrs := util.JoinErrsStr([]error{
errors.New(`'description' cannot be blank`),
@@ -106,9 +107,12 @@ func TestValidate(t *testing.T) {
APIInfoImpl: api.APIInfoImpl{ReqInfo: &reqInfo},
Role: role,
}
- err := r.Validate()
- if err != nil {
- t.Errorf("expected nil, got %s", err)
+ userErr, sysErr := r.Validate()
+ if userErr != nil {
+ t.Errorf("expected nil user error, got: %s", userErr)
+ }
+ if sysErr != nil {
+ t.Errorf("expected nil system error, got: %v", sysErr)
}
}
diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go
index ffe5f41183..205fe98077 100644
--- a/traffic_ops/traffic_ops_golang/server/servers.go
+++ b/traffic_ops/traffic_ops_golang/server/servers.go
@@ -402,7 +402,7 @@ func newUUID() *string {
return &uuidReference
}
-func validateCommon(s *tc.CommonServerProperties, tx *sql.Tx) []error {
+func validateCommon(s *tc.CommonServerProperties, tx *sql.Tx) ([]error, error) {
noSpaces := validation.NewStringRule(tovalidate.NoSpaces, "cannot contain spaces")
@@ -420,7 +420,7 @@ func validateCommon(s *tc.CommonServerProperties, tx *sql.Tx) []error {
})
if len(errs) > 0 {
- return errs
+ return errs, nil
}
if _, err := tc.ValidateTypeID(tx, s.TypeID, "server"); err != nil {
@@ -429,20 +429,18 @@ func validateCommon(s *tc.CommonServerProperties, tx *sql.Tx) []error {
var cdnID int
if err := tx.QueryRow("SELECT cdn from profile WHERE id=$1", s.ProfileID).Scan(&cdnID); err != nil {
- log.Errorf("could not execute select cdnID from profile: %s\n", err)
- if err == sql.ErrNoRows {
- errs = append(errs, fmt.Errorf("no such profileId: '%d'", *s.ProfileID))
- } else {
- errs = append(errs, tc.DBError)
+ if errors.Is(err, sql.ErrNoRows) {
+ errs = append(errs, fmt.Errorf("no such Profile: #%d", *s.ProfileID))
+ return errs, nil
}
- return errs
+ return nil, fmt.Errorf("could not execute select cdnID from profile: %w", err)
}
log.Infof("got cdn id: %d from profile and cdn id: %d from server", cdnID, *s.CDNID)
if cdnID != *s.CDNID {
errs = append(errs, fmt.Errorf("CDN id '%d' for profile '%d' does not match Server CDN '%d'", cdnID, *s.ProfileID, *s.CDNID))
}
- return errs
+ return errs, nil
}
func validateCommonV40(s *tc.ServerV40, tx *sql.Tx) ([]error, error) {
@@ -495,7 +493,7 @@ func validateCommonV40(s *tc.ServerV40, tx *sql.Tx) ([]error, error) {
return errs, nil
}
-func validateV1(s *tc.ServerNullableV11, tx *sql.Tx) error {
+func validateV1(s *tc.ServerNullableV11, tx *sql.Tx) (error, error) {
if s.IP6Address != nil && len(strings.TrimSpace(*s.IP6Address)) == 0 {
s.IP6Address = nil
}
@@ -520,16 +518,17 @@ func validateV1(s *tc.ServerNullableV11, tx *sql.Tx) error {
}
errs = append(errs, tovalidate.ToErrors(validateErrs)...)
- errs = append(errs, validateCommon(&s.CommonServerProperties, tx)...)
+ commonErrs, sysErr := validateCommon(&s.CommonServerProperties, tx)
+ errs = append(errs, commonErrs...)
- return util.JoinErrs(errs)
+ return util.JoinErrs(errs), sysErr
}
-func validateV2(s *tc.ServerNullableV2, tx *sql.Tx) error {
+func validateV2(s *tc.ServerNullableV2, tx *sql.Tx) (error, error) {
var errs []error
- if err := validateV1(&s.ServerNullableV11, tx); err != nil {
- return err
+ if userErr, sysErr := validateV1(&s.ServerNullableV11, tx); userErr != nil || sysErr != nil {
+ return userErr, sysErr
}
// default boolean value is false
@@ -551,7 +550,7 @@ func validateV2(s *tc.ServerNullableV2, tx *sql.Tx) error {
if *s.IP6IsService && (s.IP6Address == nil || *s.IP6Address == "") {
errs = append(errs, tc.EmptyAddressCannotBeAServiceAddressError)
}
- return util.JoinErrs(errs)
+ return util.JoinErrs(errs), nil
}
func validateMTU(mtu interface{}) error {
@@ -674,10 +673,10 @@ WHERE (profiles = $1::text[])
return serviceInterface, util.JoinErrs(errs), nil
}
-func validateV3(s *tc.ServerV30, tx *sql.Tx) (string, error) {
+func validateV3(s *tc.ServerV30, tx *sql.Tx) (string, error, error) {
if len(s.Interfaces) == 0 {
- return "", errors.New("a server must have at least one interface")
+ return "", errors.New("a server must have at least one interface"), nil
}
var errs []error
var serviceAddrV4Found bool
@@ -740,8 +739,10 @@ func validateV3(s *tc.ServerV30, tx *sql.Tx) (string, error) {
errs = append(errs, errors.New("a server must have at least one service address"))
}
- if errs = append(errs, validateCommon(&s.CommonServerProperties, tx)...); errs != nil {
- return serviceInterface, util.JoinErrs(errs)
+ commonErrs, sysErr := validateCommon(&s.CommonServerProperties, tx)
+ errs = append(errs, commonErrs...)
+ if len(errs) > 0 || sysErr != nil {
+ return serviceInterface, util.JoinErrs(errs), sysErr
}
query := `
SELECT s.ID, ip.address FROM server s
@@ -760,7 +761,7 @@ and p.id = $1
rows, err = tx.Query(query, *s.ProfileID)
}
if err != nil {
- errs = append(errs, errors.New("unable to determine service address uniqueness"))
+ return serviceInterface, util.JoinErrs(errs), fmt.Errorf("unable to determine service address uniqueness: querying: %w", err)
} else if rows != nil {
defer rows.Close()
for rows.Next() {
@@ -768,14 +769,14 @@ and p.id = $1
var ipaddress string
err = rows.Scan(&id, &ipaddress)
if err != nil {
- errs = append(errs, errors.New("unable to determine service address uniqueness"))
+ return serviceInterface, util.JoinErrs(errs), fmt.Errorf("unable to determine service address uniqueness: scanning: %w", err)
} else if (ipaddress == ipv4 || ipaddress == ipv6) && (s.ID == nil || *s.ID != id) {
errs = append(errs, fmt.Errorf("there exists a server with id %v on the same profile that has the same service address %s", id, ipaddress))
}
}
}
- return serviceInterface, util.JoinErrs(errs)
+ return serviceInterface, util.JoinErrs(errs), nil
}
// Read is the handler for GET requests to /servers.
@@ -1515,9 +1516,13 @@ func Update(w http.ResponseWriter, r *http.Request) {
serverV3.StatusLastUpdated = original.StatusLastUpdated
statusLastUpdatedTime = *original.StatusLastUpdated
}
- _, err := validateV3(&serverV3, tx)
- if err != nil {
- api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+ _, userErr, sysErr := validateV3(&serverV3, tx)
+ if userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ api.HandleErr(w, r, tx, code, userErr, sysErr)
return
}
profileName, err := dbhelpers.UpdateServerProfileTableForV2V3(serverV3.ID, serverV3.ProfileID, (original.ProfileNames)[0], tx)
@@ -1542,9 +1547,13 @@ func Update(w http.ResponseWriter, r *http.Request) {
api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
return
}
- err := validateV2(&legacyServer, tx)
- if err != nil {
- api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil)
+ userErr, sysErr := validateV2(&legacyServer, tx)
+ if userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ api.HandleErr(w, r, tx, code, userErr, sysErr)
return
}
profileName, err := dbhelpers.UpdateServerProfileTableForV2V3(legacyServer.ID, legacyServer.ProfileID, (original.ProfileNames)[0], tx)
@@ -1811,8 +1820,8 @@ func insertServerProfile(id int, pName []string, tx *sql.Tx) (error, error, int)
}
insertQuery := `
INSERT INTO server_profile (
- server,
- profile_name,
+ server,
+ profile_name,
priority
)SELECT $1, profile_name, priority
FROM UNNEST($2::text[], $3::int[]) WITH ORDINALITY AS tmp(profile_name, priority)
@@ -1847,8 +1856,12 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) {
server.XMPPID = newUUID()
- if err := validateV2(&server, inf.Tx.Tx); err != nil {
- api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, err, nil)
+ if userErr, sysErr := validateV2(&server, inf.Tx.Tx); userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ api.HandleErr(w, r, inf.Tx.Tx, code, userErr, sysErr)
return
}
@@ -1984,9 +1997,13 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) {
server.XMPPID = newUUID()
- _, err := validateV3(&server, inf.Tx.Tx)
- if err != nil {
- api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, err, nil)
+ _, userErr, sysErr := validateV3(&server, inf.Tx.Tx)
+ if userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ api.HandleErr(w, r, inf.Tx.Tx, code, userErr, sysErr)
return
}
diff --git a/traffic_ops/traffic_ops_golang/server/servers_assignment.go b/traffic_ops/traffic_ops_golang/server/servers_assignment.go
index d9f0d87ac3..0107a9db89 100644
--- a/traffic_ops/traffic_ops_golang/server/servers_assignment.go
+++ b/traffic_ops/traffic_ops_golang/server/servers_assignment.go
@@ -432,8 +432,7 @@ INSERT INTO parameter (config_file, name, value)
for rows.Next() {
var ID int64
if err := rows.Scan(&ID); err != nil {
- log.Errorf("could not scan parameter ID: %s\n", err)
- return nil, tc.DBError
+ return nil, fmt.Errorf("could not scan parameter ID: %w", err)
}
parameterIds = append(parameterIds, ID)
}
diff --git a/traffic_ops/traffic_ops_golang/server/servers_server_capability.go b/traffic_ops/traffic_ops_golang/server/servers_server_capability.go
index ef56814e28..64291f21cd 100644
--- a/traffic_ops/traffic_ops_golang/server/servers_server_capability.go
+++ b/traffic_ops/traffic_ops_golang/server/servers_server_capability.go
@@ -112,14 +112,14 @@ func (ssc *TOServerServerCapability) GetType() string {
return "server server_capability"
}
-// Validate fulfills the api.Validator interface
-func (ssc TOServerServerCapability) Validate() error {
+// Validate fulfills the api.Validator interface.
+func (ssc TOServerServerCapability) Validate() (error, error) {
errs := validation.Errors{
ServerQueryParam: validation.Validate(ssc.ServerID, validation.Required),
ServerCapabilityQueryParam: validation.Validate(ssc.ServerCapability, validation.Required),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (ssc *TOServerServerCapability) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
@@ -375,7 +375,7 @@ SELECT ARRAY(
SELECT dsrc.deliveryservice_id
FROM deliveryservices_required_capability as dsrc
WHERE deliveryservice_id IN (
- SELECT deliveryservice
+ SELECT deliveryservice
FROM deliveryservice_server
WHERE server = $1)
AND dsrc.required_capability = $2)`
diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go
index 94b33aa2a6..8283284143 100644
--- a/traffic_ops/traffic_ops_golang/server/servers_test.go
+++ b/traffic_ops/traffic_ops_golang/server/servers_test.go
@@ -575,7 +575,7 @@ func TestV3Validations(t *testing.T) {
tx := db.MustBegin().Tx
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err != nil {
t.Errorf("Unexpected error validating test server: %v", err)
}
@@ -587,7 +587,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server with no interfaces to be invalid")
} else {
@@ -601,7 +601,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server with nil interfaces to be invalid")
} else {
@@ -618,7 +618,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server an MTU < 1280 to be invalid")
} else {
@@ -634,7 +634,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server with no IP addresses to be invalid")
} else {
@@ -649,7 +649,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server with nil IP addresses to be invalid")
} else {
@@ -670,7 +670,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server with no service addresses to be invalid")
} else {
@@ -684,7 +684,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server with too many interfaces with service addresses to be invalid")
} else {
@@ -704,7 +704,7 @@ func TestV3Validations(t *testing.T) {
mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows)
mock.ExpectQuery("SELECT").WillReturnRows(cdnRows)
- _, err = validateV3(&testServer, tx)
+ _, err, _ = validateV3(&testServer, tx)
if err == nil {
t.Errorf("Expected a server with no service addresses to be invalid")
} else {
diff --git a/traffic_ops/traffic_ops_golang/server/servers_update_status.go b/traffic_ops/traffic_ops_golang/server/servers_update_status.go
index b395547575..bdc2e9aa0d 100644
--- a/traffic_ops/traffic_ops_golang/server/servers_update_status.go
+++ b/traffic_ops/traffic_ops_golang/server/servers_update_status.go
@@ -21,6 +21,7 @@ package server
import (
"database/sql"
+ "fmt"
"net/http"
"github.com/lib/pq"
@@ -39,7 +40,7 @@ func GetServerUpdateStatusHandler(w http.ResponseWriter, r *http.Request) {
}
defer inf.Close()
- serverUpdateStatuses, err := getServerUpdateStatus(inf.Tx.Tx, inf.Config, inf.Params["host_name"])
+ serverUpdateStatuses, err, _ := getServerUpdateStatus(inf.Tx.Tx, inf.Config, inf.Params["host_name"])
if err != nil {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, err)
return
@@ -55,7 +56,7 @@ func GetServerUpdateStatusHandler(w http.ResponseWriter, r *http.Request) {
}
}
-func getServerUpdateStatus(tx *sql.Tx, cfg *config.Config, hostName string) ([]tc.ServerUpdateStatusV40, error) {
+func getServerUpdateStatus(tx *sql.Tx, cfg *config.Config, hostName string) ([]tc.ServerUpdateStatusV40, error, error) {
updateStatuses := []tc.ServerUpdateStatusV40{}
@@ -86,7 +87,7 @@ UNION ALL
* ancestor topology node found by topology_ancestors.
*/
), server_topology_ancestors AS (
-SELECT s.id,
+SELECT s.id,
s.cachegroup,
s.cdn_id,
s.config_update_time > s.config_apply_time AS upd_pending,
@@ -99,7 +100,7 @@ SELECT s.id,
JOIN status ON status.id = s.status
WHERE status.name = ANY($1::TEXT[])
), parentservers AS (
-SELECT ps.id,
+SELECT ps.id,
ps.cachegroup,
ps.cdn_id,
ps.config_update_time > ps.config_apply_time AS upd_pending,
@@ -160,7 +161,7 @@ ORDER BY s.id
rows, err := tx.Query(selectQuery, pq.Array(cacheStatusesToCheck), tc.UseRevalPendingParameterName, tc.GlobalConfigFileName, pq.Array(cacheGroupTypes), hostName)
if err != nil {
log.Errorf("could not execute query: %s\n", err)
- return nil, tc.DBError
+ return nil, nil, fmt.Errorf("could not execute query: %w", err)
}
defer log.Close(rows, "getServerUpdateStatus(): unable to close db connection")
@@ -168,10 +169,9 @@ ORDER BY s.id
var us tc.ServerUpdateStatusV40
var serverType string
if err := rows.Scan(&us.HostId, &us.HostName, &serverType, &us.RevalPending, &us.UseRevalPending, &us.UpdatePending, &us.Status, &us.ParentPending, &us.ParentRevalPending, &us.ConfigUpdateTime, &us.ConfigApplyTime, &us.RevalidateUpdateTime, &us.RevalidateApplyTime); err != nil {
- log.Errorf("could not scan server update status: %s\n", err)
- return nil, tc.DBError
+ return nil, nil, fmt.Errorf("could not scan server update status: %w", err)
}
updateStatuses = append(updateStatuses, us)
}
- return updateStatuses, nil
+ return updateStatuses, nil, nil
}
diff --git a/traffic_ops/traffic_ops_golang/server/servers_update_status_test.go b/traffic_ops/traffic_ops_golang/server/servers_update_status_test.go
index 6f20fc6c2e..bdcbf4e91a 100644
--- a/traffic_ops/traffic_ops_golang/server/servers_update_status_test.go
+++ b/traffic_ops/traffic_ops_golang/server/servers_update_status_test.go
@@ -58,7 +58,7 @@ func TestGetServerUpdateStatus(t *testing.T) {
}
defer tx.Commit()
- result, err := getServerUpdateStatus(tx, &config.Config{ConfigTrafficOpsGolang: config.ConfigTrafficOpsGolang{DBQueryTimeoutSeconds: 20}}, "host_name_1")
+ result, err, _ := getServerUpdateStatus(tx, &config.Config{ConfigTrafficOpsGolang: config.ConfigTrafficOpsGolang{DBQueryTimeoutSeconds: 20}}, "host_name_1")
if err != nil {
t.Errorf("getServerUpdateStatus: %v", err)
}
diff --git a/traffic_ops/traffic_ops_golang/servercapability/servercapability.go b/traffic_ops/traffic_ops_golang/servercapability/servercapability.go
index 383c1cfaff..daffb54387 100644
--- a/traffic_ops/traffic_ops_golang/servercapability/servercapability.go
+++ b/traffic_ops/traffic_ops_golang/servercapability/servercapability.go
@@ -107,12 +107,12 @@ func (v *TOServerCapability) GetType() string {
return "server capability"
}
-func (v *TOServerCapability) Validate() error {
+func (v *TOServerCapability) Validate() (error, error) {
rule := validation.NewStringRule(tovalidate.IsAlphanumericUnderscoreDash, "must consist of only alphanumeric, dash, or underscore characters")
errs := validation.Errors{
"name": validation.Validate(v.Name, validation.Required, rule),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (v *TOServerCapability) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
diff --git a/traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go b/traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go
index 893eaf978f..f3e46e96f5 100644
--- a/traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go
+++ b/traffic_ops/traffic_ops_golang/servicecategory/servicecategories.go
@@ -31,7 +31,7 @@ import (
"github.com/apache/trafficcontrol/lib/go-util"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
- "github.com/go-ozzo/ozzo-validation"
+ validation "github.com/go-ozzo/ozzo-validation"
)
type TOServiceCategory struct {
@@ -91,12 +91,12 @@ func (serviceCategory *TOServiceCategory) SelectMaxLastUpdatedQuery(where, order
select max(last_updated) as t from last_deleted l where l.table_name='service_category') as res`
}
-func (serviceCategory TOServiceCategory) Validate() error {
+func (serviceCategory TOServiceCategory) Validate() (error, error) {
nameRule := validation.NewStringRule(tovalidate.IsAlphanumericDash, "must consist of only alphanumeric or dash characters.")
errs := validation.Errors{
"name": validation.Validate(serviceCategory.Name, validation.Required, nameRule),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (serviceCategory *TOServiceCategory) Create() (error, error, int) {
@@ -129,8 +129,12 @@ func Update(w http.ResponseWriter, r *http.Request) {
return
}
- if err := newSC.Validate(); err != nil {
- api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest, err, nil)
+ if userErr, sysErr := newSC.Validate(); userErr != nil || sysErr != nil {
+ code := http.StatusBadRequest
+ if sysErr != nil {
+ code = http.StatusInternalServerError
+ }
+ api.HandleErr(w, r, inf.Tx.Tx, code, userErr, sysErr)
return
}
diff --git a/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go b/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go
index 5030dc4e83..298964913f 100644
--- a/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go
+++ b/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go
@@ -94,11 +94,11 @@ func (staticDNSEntry *TOStaticDNSEntry) SetKeys(keys map[string]interface{}) {
staticDNSEntry.ID = &i
}
-// Validate fulfills the api.Validator interface
-func (staticDNSEntry TOStaticDNSEntry) Validate() error {
+// Validate fulfills the api.Validator interface.
+func (staticDNSEntry TOStaticDNSEntry) Validate() (error, error) {
typeStr, err := tc.ValidateTypeID(staticDNSEntry.ReqInfo.Tx.Tx, &staticDNSEntry.TypeID, "staticdnsentry")
if err != nil {
- return err
+ return err, nil
}
var addressErr, ttlErr error
@@ -135,7 +135,7 @@ func (staticDNSEntry TOStaticDNSEntry) Validate() error {
"ttl": ttlErr,
"typeId": validation.Validate(staticDNSEntry.TypeID, validation.Required),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (en *TOStaticDNSEntry) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
diff --git a/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry_test.go b/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry_test.go
index c0c34eaf90..40a08c45da 100644
--- a/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry_test.go
+++ b/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry_test.go
@@ -89,7 +89,8 @@ func TestValidate(t *testing.T) {
reqInfo := api.APIInfo{Tx: tx}
// invalid name, empty domainname
ts := TOStaticDNSEntry{APIInfoImpl: api.APIInfoImpl{ReqInfo: &reqInfo}}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(ts.Validate())))
+ err, _ = ts.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expectedErrs := util.JoinErrsStr([]error{
errors.New(`'address' cannot be blank`),
diff --git a/traffic_ops/traffic_ops_golang/status/statuses.go b/traffic_ops/traffic_ops_golang/status/statuses.go
index 875edce434..24f7bc38cc 100644
--- a/traffic_ops/traffic_ops_golang/status/statuses.go
+++ b/traffic_ops/traffic_ops_golang/status/statuses.go
@@ -94,11 +94,11 @@ func (status TOStatus) GetAuditName() string {
func (status TOStatus) GetType() string { return "status" }
-func (status TOStatus) Validate() error {
+func (status TOStatus) Validate() (error, error) {
errs := validation.Errors{
"name": validation.Validate(status.Name, validation.NotNil, validation.Required),
}
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
func (st *TOStatus) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
diff --git a/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go b/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go
index 091d6cb9da..46023832c1 100644
--- a/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go
+++ b/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets.go
@@ -94,7 +94,7 @@ func (st TOSteeringTargetV11) GetType() string {
return "steeringtarget"
}
-func (st TOSteeringTargetV11) Validate() error {
+func (st TOSteeringTargetV11) Validate() (error, error) {
return st.SteeringTargetNullable.Validate(st.ReqInfo.Tx.Tx)
}
diff --git a/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets_test.go b/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets_test.go
index 2a79a232a0..fe8fe0074a 100644
--- a/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets_test.go
+++ b/traffic_ops/traffic_ops_golang/steeringtargets/steeringtargets_test.go
@@ -20,12 +20,13 @@ package steeringtargets
*/
import (
+ "testing"
+
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/lib/go-util"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
"github.com/jmoiron/sqlx"
"gopkg.in/DATA-DOG/go-sqlmock.v1"
- "testing"
)
func TestInvalidSteeringTargetType(t *testing.T) {
@@ -82,7 +83,7 @@ func TestInvalidSteeringTargetType(t *testing.T) {
LastUpdated: nil,
}
- err = stObj.Validate()
+ err, _ = stObj.Validate()
if err == nil {
t.Fatal("expected user error to say that type is invalid, got no error instead")
}
diff --git a/traffic_ops/traffic_ops_golang/topology/topologies.go b/traffic_ops/traffic_ops_golang/topology/topologies.go
index f9fb81dea7..df9ead8bbd 100644
--- a/traffic_ops/traffic_ops_golang/topology/topologies.go
+++ b/traffic_ops/traffic_ops_golang/topology/topologies.go
@@ -89,7 +89,7 @@ func (topology *TOTopology) GetType() string {
}
// Validate is a requirement of the api.Validator interface.
-func (topology *TOTopology) Validate() error {
+func (topology *TOTopology) Validate() (error, error) {
currentTopoName := topology.APIInfoImpl.ReqInfo.Params["name"]
nameRule := validation.NewStringRule(tovalidate.IsAlphanumericUnderscoreDash, "must consist of only alphanumeric, dash, or underscore characters.")
rules := validation.Errors{}
@@ -117,12 +117,7 @@ func (topology *TOTopology) Validate() error {
cacheGroupNames[index] = node.Cachegroup
}
if cacheGroupMap, userErr, sysErr, _ = cachegroup.GetCacheGroupsByName(cacheGroupNames, topology.APIInfoImpl.ReqInfo.Tx); userErr != nil || sysErr != nil {
- var err error
- message := "could not get cachegroups"
- if userErr != nil {
- err = fmt.Errorf("%s: %s", message, userErr.Error())
- }
- return err
+ return userErr, sysErr
}
cacheGroups = make([]tc.CacheGroupNullable, len(topology.Nodes))
for index, node := range topology.Nodes {
@@ -133,7 +128,7 @@ func (topology *TOTopology) Validate() error {
}
rules["duplicate cachegroup name"] = checkUniqueCacheGroupNames(topology.Nodes)
if !cacheGroupsExist {
- return util.JoinErrs(tovalidate.ToErrors(rules))
+ return util.JoinErrs(tovalidate.ToErrors(rules)), nil
}
for index, node := range topology.Nodes {
@@ -146,8 +141,7 @@ func (topology *TOTopology) Validate() error {
}
dsCDNs, err := dbhelpers.GetDeliveryServiceCDNsByTopology(topology.ReqInfo.Tx.Tx, currentTopoName)
if err != nil {
- log.Errorf("validating topology: %v", err)
- return errors.New("unable to validate topology")
+ return errors.New("unable to validate topology"), fmt.Errorf("validating Topology: %w", err)
}
rules["empty cachegroups"] = topology_validation.CheckForEmptyCacheGroups(topology.ReqInfo.Tx, cacheGroupIds, dsCDNs, false, nil)
rules["required capabilities"] = topology.validateDSRequiredCapabilities(currentTopoName)
@@ -155,17 +149,13 @@ func (topology *TOTopology) Validate() error {
//Get current Topology-CG for the requested change.
topoCachegroupNames := topology.getCachegroupNames()
userErr, sysErr, _ = dbhelpers.CheckTopologyOrgServerCGInDSCG(topology.ReqInfo.Tx.Tx, dsCDNs, currentTopoName, topoCachegroupNames)
- if userErr != nil {
- return userErr
- }
- if sysErr != nil {
- log.Errorf("error while validate topology: %s", sysErr.Error())
- return errors.New("unable to validate topology")
+ if userErr != nil || sysErr != nil {
+ return userErr, sysErr
}
/* Only perform further checks if everything so far is valid */
if err = util.JoinErrs(tovalidate.ToErrors(rules)); err != nil {
- return err
+ return err, nil
}
for _, leafMid := range checkForLeafMids(topology.Nodes, cacheGroups) {
@@ -174,7 +164,7 @@ func (topology *TOTopology) Validate() error {
_, rules["topology cycles"] = checkForCycles(topology.Nodes)
rules["super-topology cycles"] = topology.checkForCyclesAcrossTopologies()
- return util.JoinErrs(tovalidate.ToErrors(rules))
+ return util.JoinErrs(tovalidate.ToErrors(rules)), nil
}
func (topology *TOTopology) nodesInOtherTopologies() ([]tc.TopologyNode, map[string][]string, error) {
diff --git a/traffic_ops/traffic_ops_golang/types/types.go b/traffic_ops/traffic_ops_golang/types/types.go
index 8229779ecb..f16051c725 100644
--- a/traffic_ops/traffic_ops_golang/types/types.go
+++ b/traffic_ops/traffic_ops_golang/types/types.go
@@ -94,16 +94,16 @@ func (typ *TOType) GetType() string {
return "type"
}
-func (typ *TOType) Validate() error {
+func (typ *TOType) Validate() (error, error) {
errs := validation.Errors{
"name": validation.Validate(typ.Name, validation.Required),
"description": validation.Validate(typ.Description, validation.Required),
"use_in_table": validation.Validate(typ.UseInTable, validation.Required),
}
if errs != nil {
- return util.JoinErrs(tovalidate.ToErrors(errs))
+ return util.JoinErrs(tovalidate.ToErrors(errs)), nil
}
- return nil
+ return nil, nil
}
func (tp *TOType) Read(h http.Header, useIMS bool) ([]interface{}, error, error, int, *time.Time) {
diff --git a/traffic_ops/traffic_ops_golang/types/types_test.go b/traffic_ops/traffic_ops_golang/types/types_test.go
index 529417de56..3ad395401c 100644
--- a/traffic_ops/traffic_ops_golang/types/types_test.go
+++ b/traffic_ops/traffic_ops_golang/types/types_test.go
@@ -181,7 +181,8 @@ func TestCreateInvalidType(t *testing.T) {
func TestValidate(t *testing.T) {
p := TOType{}
- errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(p.Validate())))
+ err, _ := p.Validate()
+ errs := util.JoinErrsStr(test.SortErrors(test.SplitErrors(err)))
expected := util.JoinErrsStr(test.SortErrors([]error{
errors.New("'name' cannot be blank"),
errors.New("'description' cannot be blank"),
diff --git a/traffic_ops/traffic_ops_golang/user/user.go b/traffic_ops/traffic_ops_golang/user/user.go
index 8cd9df7b75..89b3fea9a2 100644
--- a/traffic_ops/traffic_ops_golang/user/user.go
+++ b/traffic_ops/traffic_ops_golang/user/user.go
@@ -40,7 +40,7 @@ import (
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/util/ims"
- "github.com/go-ozzo/ozzo-validation"
+ validation "github.com/go-ozzo/ozzo-validation"
"github.com/go-ozzo/ozzo-validation/is"
"github.com/jmoiron/sqlx"
)
@@ -97,7 +97,7 @@ func (user *TOUser) ParamColumns() map[string]dbhelpers.WhereColumnInfo {
}
}
-func (user *TOUser) Validate() error {
+func (user *TOUser) Validate() (error, error) {
validateErrs := validation.Errors{
"email": validation.Validate(user.Email, validation.Required, is.Email),
@@ -111,11 +111,11 @@ func (user *TOUser) Validate() error {
if user.LocalPassword != nil {
_, err := auth.IsGoodLoginPair(*user.Username, *user.LocalPassword)
if err != nil {
- return err
+ return err, nil
}
}
- return util.JoinErrs(tovalidate.ToErrors(validateErrs))
+ return util.JoinErrs(tovalidate.ToErrors(validateErrs)), nil
}
func (user *TOUser) postValidate() error {