From ccebb4414253fc855f5ce66c111e646e636c61ed Mon Sep 17 00:00:00 2001 From: hemanthKa677 Date: Thu, 22 Feb 2024 11:52:54 +0530 Subject: [PATCH 01/13] adds generic function for search by alt id --- object_manager.go | 96 +++++++++++++++++++++++++++++++++++++++++++++++ utils.go | 7 ++++ 2 files changed, 103 insertions(+) diff --git a/object_manager.go b/object_manager.go index 5f8e7b2d..e5b0b751 100644 --- a/object_manager.go +++ b/object_manager.go @@ -77,6 +77,7 @@ type IBObjectManager interface { GetAllMembers() ([]Member, error) GetGridInfo() ([]Grid, error) GetGridLicense() ([]License, error) + SearchDnsObjectByAltId(objType string, internalId string, ref string, eaNameForInternalId string) (interface{}, error) ReleaseIP(netview string, cidr string, ipAddr string, isIPv6 bool, macAddr string) (string, error) UpdateAAAARecord(ref string, netView string, recordName string, cidr string, ipAddr string, useTtl bool, ttl uint32, comment string, setEas EA) (*RecordAAAA, error) UpdateCNAMERecord(ref string, canonical string, recordName string, useTtl bool, ttl uint32, comment string, setEas EA) (*RecordCNAME, error) @@ -301,3 +302,98 @@ func (objMgr *ObjectManager) UpdateZoneDelegated(ref string, delegate_to []NameS func (objMgr *ObjectManager) DeleteZoneDelegated(ref string) (string, error) { return objMgr.connector.DeleteObject(ref) } + +// Generic function to search object by alternate id +func (objMgr *ObjectManager) SearchDnsObjectByAltId( + objType string, ref string, internalId string, eaNameForInternalId string) (interface{}, error) { + var err error + if internalId == "" { + return nil, fmt.Errorf("internal ID must not be empty") + } + + var recordType GenericObj + + switch objType { + case "A": + recordType = NewEmptyRecordA() + case "AAAA": + recordType = NewEmptyRecordAAAA() + case "CNAME": + recordType = NewEmptyRecordCNAME() + case "MX": + recordType = NewEmptyRecordMX() + default: + return nil, fmt.Errorf("unknown record type") + } + var res interface{} + if ref != "" { + if err := objMgr.connector.GetObject(recordType, ref, NewQueryParams(false, nil), &res); err != nil { + fmt.Println("Error ", err.Error()) + if _, ok := err.(*NotFoundError); !ok { + return nil, err + } + } + } + + sf := map[string]string{ + fmt.Sprintf("*%s", eaNameForInternalId): internalId, + } + var val interface{} + switch objType { + case "A": + if recordType.(*RecordA).Ref != "" { + return &res, nil + } + + err = objMgr.connector.GetObject(NewEmptyRecordA(), "", NewQueryParams(false, sf), &val) + //res = make([]HostRecord, 0) + var newVal []RecordA + byteVal, _ := json.Marshal(val) + json.Unmarshal(byteVal, &newVal) + res = newVal + case "AAAA": + if recordType.(*RecordAAAA).Ref != "" { + return &res, nil + } + + err = objMgr.connector.GetObject(NewEmptyRecordAAAA(), "", NewQueryParams(false, sf), &val) + //res = make([]HostRecord, 0) + var newVal []RecordAAAA + byteVal, _ := json.Marshal(val) + json.Unmarshal(byteVal, &newVal) + res = newVal + case "CNAME": + if recordType.(*RecordCNAME).Ref != "" { + return &res, nil + } + + err = objMgr.connector.GetObject(NewEmptyRecordCNAME(), "", NewQueryParams(false, sf), &val) + //res = make([]HostRecord, 0) + var newVal []RecordCNAME + byteVal, _ := json.Marshal(val) + json.Unmarshal(byteVal, &newVal) + res = newVal + case "MX": + if recordType.(*RecordMX).Ref != "" { + return &res, nil + } + + err = objMgr.connector.GetObject(NewEmptyRecordMX(), "", NewQueryParams(false, sf), &val) + //res = make([]HostRecord, 0) + var newVal []RecordMX + byteVal, _ := json.Marshal(val) + json.Unmarshal(byteVal, &newVal) + res = newVal + } + + if err != nil { + return nil, err + } + + if res == nil { + return nil, NewNotFoundError("record not found") + } + + result := res + return &result, nil +} diff --git a/utils.go b/utils.go index 6e44fdf8..06b8c3cf 100644 --- a/utils.go +++ b/utils.go @@ -22,6 +22,13 @@ func NewNotFoundError(msg string) *NotFoundError { return &NotFoundError{msg: msg} } +type GenericObj interface { + ObjectType() string + ReturnFields() []string + EaSearch() EASearch + SetReturnFields([]string) +} + func BuildNetworkViewFromRef(ref string) *NetworkView { // networkview/ZG5zLm5ldHdvcmtfdmlldyQyMw:global_view/false r := regexp.MustCompile(`networkview/\w+:([^/]+)/\w+`) From 0c4dcfe63c1b19a64f9bdf404adbeac7daae0f6c Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Thu, 22 Feb 2024 16:25:15 +0530 Subject: [PATCH 02/13] Modified the generic code by replacing the switch case with dictionary. --- object_manager.go | 204 ++++++++++++++++++++++++++++++---------------- 1 file changed, 132 insertions(+), 72 deletions(-) diff --git a/object_manager.go b/object_manager.go index e5b0b751..9c50988e 100644 --- a/object_manager.go +++ b/object_manager.go @@ -98,6 +98,101 @@ type IBObjectManager interface { UpdateDhcpStatus(ref string, status bool) (Dhcp, error) } +// Map of record type to its corresponding object +var getRecordTypeMap = map[string]func() IBObject{ + "A": func() IBObject { + return NewEmptyRecordA() + }, + "AAAA": func() IBObject { + return NewEmptyRecordAAAA() + }, + "CNAME": func() IBObject { + return NewEmptyRecordCNAME() + }, + "MX": func() IBObject { + return NewEmptyRecordMX() + }, +} + +// Map returns the object with search fields with the given record type +var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error){ + "A": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*RecordA).Ref != "" { + return res, nil + } + + err := objMgr.connector.GetObject(NewEmptyRecordA(), "", NewQueryParams(false, sf), &res) + var newVal []RecordA + byteVal, err := json.Marshal(res) + if err != nil { + return nil, err + } + err = json.Unmarshal(byteVal, &newVal) + if err != nil { + return nil, err + } + res = newVal + return res, err + }, + "AAAA": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*RecordAAAA).Ref != "" { + return res, nil + } + + err := objMgr.connector.GetObject(NewEmptyRecordAAAA(), "", NewQueryParams(false, sf), &res) + var newVal []RecordAAAA + byteVal, err := json.Marshal(res) + if err != nil { + return nil, err + } + err = json.Unmarshal(byteVal, &newVal) + if err != nil { + return nil, err + } + res = newVal + return res, err + }, + "CNAME": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*RecordCNAME).Ref != "" { + return res, nil + } + err := objMgr.connector.GetObject(NewEmptyRecordCNAME(), "", NewQueryParams(false, sf), &res) + var newVal []RecordCNAME + byteVal, err := json.Marshal(res) + if err != nil { + return nil, err + } + err = json.Unmarshal(byteVal, &newVal) + if err != nil { + return nil, err + } + res = newVal + return res, err + }, + "MX": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*RecordMX).Ref != "" { + return res, nil + } + err := objMgr.connector.GetObject(NewEmptyRecordMX(), "", NewQueryParams(false, sf), &res) + var newVal []RecordMX + byteVal, err := json.Marshal(res) + if err != nil { + return nil, err + } + err = json.Unmarshal(byteVal, &newVal) + if err != nil { + return nil, err + } + res = newVal + return res, err + + }, +} + type ObjectManager struct { connector IBConnector cmpType string @@ -162,7 +257,8 @@ func (objMgr *ObjectManager) GetAllMembers() ([]Member, error) { memberObj := NewMember(Member{}) err := objMgr.connector.GetObject( - memberObj, "", NewQueryParams(false, nil), &res) + memberObj, "", NewQueryParams(false, nil), &res, + ) return res, err } @@ -186,7 +282,8 @@ func (objMgr *ObjectManager) GetLicense() ([]License, error) { licenseObj := NewLicense(License{}) err := objMgr.connector.GetObject( - licenseObj, "", NewQueryParams(false, nil), &res) + licenseObj, "", NewQueryParams(false, nil), &res, + ) return res, err } @@ -196,7 +293,8 @@ func (objMgr *ObjectManager) GetGridLicense() ([]License, error) { licenseObj := NewGridLicense(License{}) err := objMgr.connector.GetObject( - licenseObj, "", NewQueryParams(false, nil), &res) + licenseObj, "", NewQueryParams(false, nil), &res, + ) return res, err } @@ -206,7 +304,8 @@ func (objMgr *ObjectManager) GetGridInfo() ([]Grid, error) { gridObj := NewGrid(Grid{}) err := objMgr.connector.GetObject( - gridObj, "", NewQueryParams(false, nil), &res) + gridObj, "", NewQueryParams(false, nil), &res, + ) return res, err } @@ -215,9 +314,11 @@ func (objMgr *ObjectManager) CreateZoneAuth( fqdn string, eas EA) (*ZoneAuth, error) { - zoneAuth := NewZoneAuth(ZoneAuth{ - Fqdn: fqdn, - Ea: eas}) + zoneAuth := NewZoneAuth( + ZoneAuth{ + Fqdn: fqdn, + Ea: eas}, + ) ref, err := objMgr.connector.CreateObject(zoneAuth) zoneAuth.Ref = ref @@ -233,7 +334,8 @@ func (objMgr *ObjectManager) GetZoneAuthByRef(ref string) (*ZoneAuth, error) { } err := objMgr.connector.GetObject( - res, ref, NewQueryParams(false, nil), res) + res, ref, NewQueryParams(false, nil), res, + ) return res, err } @@ -248,7 +350,8 @@ func (objMgr *ObjectManager) GetZoneAuth() ([]ZoneAuth, error) { zoneAuth := NewZoneAuth(ZoneAuth{}) err := objMgr.connector.GetObject( - zoneAuth, "", NewQueryParams(false, nil), &res) + zoneAuth, "", NewQueryParams(false, nil), &res, + ) return res, err } @@ -277,9 +380,11 @@ func (objMgr *ObjectManager) GetZoneDelegated(fqdn string) (*ZoneDelegated, erro // CreateZoneDelegated creates delegated zone func (objMgr *ObjectManager) CreateZoneDelegated(fqdn string, delegate_to []NameServer) (*ZoneDelegated, error) { - zoneDelegated := NewZoneDelegated(ZoneDelegated{ - Fqdn: fqdn, - DelegateTo: delegate_to}) + zoneDelegated := NewZoneDelegated( + ZoneDelegated{ + Fqdn: fqdn, + DelegateTo: delegate_to}, + ) ref, err := objMgr.connector.CreateObject(zoneDelegated) zoneDelegated.Ref = ref @@ -289,9 +394,11 @@ func (objMgr *ObjectManager) CreateZoneDelegated(fqdn string, delegate_to []Name // UpdateZoneDelegated updates delegated zone func (objMgr *ObjectManager) UpdateZoneDelegated(ref string, delegate_to []NameServer) (*ZoneDelegated, error) { - zoneDelegated := NewZoneDelegated(ZoneDelegated{ - Ref: ref, - DelegateTo: delegate_to}) + zoneDelegated := NewZoneDelegated( + ZoneDelegated{ + Ref: ref, + DelegateTo: delegate_to}, + ) refResp, err := objMgr.connector.UpdateObject(zoneDelegated, ref) zoneDelegated.Ref = refResp @@ -311,20 +418,13 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( return nil, fmt.Errorf("internal ID must not be empty") } - var recordType GenericObj - - switch objType { - case "A": - recordType = NewEmptyRecordA() - case "AAAA": - recordType = NewEmptyRecordAAAA() - case "CNAME": - recordType = NewEmptyRecordCNAME() - case "MX": - recordType = NewEmptyRecordMX() - default: + var recordType IBObject + if getRecordTypeMap[objType] != nil { + recordType = getRecordTypeMap[objType]() + } else { return nil, fmt.Errorf("unknown record type") } + var res interface{} if ref != "" { if err := objMgr.connector.GetObject(recordType, ref, NewQueryParams(false, nil), &res); err != nil { @@ -338,52 +438,12 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( sf := map[string]string{ fmt.Sprintf("*%s", eaNameForInternalId): internalId, } - var val interface{} - switch objType { - case "A": - if recordType.(*RecordA).Ref != "" { - return &res, nil - } - - err = objMgr.connector.GetObject(NewEmptyRecordA(), "", NewQueryParams(false, sf), &val) - //res = make([]HostRecord, 0) - var newVal []RecordA - byteVal, _ := json.Marshal(val) - json.Unmarshal(byteVal, &newVal) - res = newVal - case "AAAA": - if recordType.(*RecordAAAA).Ref != "" { - return &res, nil - } - err = objMgr.connector.GetObject(NewEmptyRecordAAAA(), "", NewQueryParams(false, sf), &val) - //res = make([]HostRecord, 0) - var newVal []RecordAAAA - byteVal, _ := json.Marshal(val) - json.Unmarshal(byteVal, &newVal) - res = newVal - case "CNAME": - if recordType.(*RecordCNAME).Ref != "" { - return &res, nil - } - - err = objMgr.connector.GetObject(NewEmptyRecordCNAME(), "", NewQueryParams(false, sf), &val) - //res = make([]HostRecord, 0) - var newVal []RecordCNAME - byteVal, _ := json.Marshal(val) - json.Unmarshal(byteVal, &newVal) - res = newVal - case "MX": - if recordType.(*RecordMX).Ref != "" { - return &res, nil - } - - err = objMgr.connector.GetObject(NewEmptyRecordMX(), "", NewQueryParams(false, sf), &val) - //res = make([]HostRecord, 0) - var newVal []RecordMX - byteVal, _ := json.Marshal(val) - json.Unmarshal(byteVal, &newVal) - res = newVal + // Fetch the object by search fields + if getObjectWithSearchFieldsMap[objType] != nil { + res, err = getObjectWithSearchFieldsMap[objType](recordType, objMgr, sf) + } else { + return nil, fmt.Errorf("unknown record type") } if err != nil { From 4a59ac342feefe3e05eb16ac2edafd15cc291569 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Fri, 23 Feb 2024 12:16:30 +0530 Subject: [PATCH 03/13] Added empty checks. --- object_manager.go | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/object_manager.go b/object_manager.go index 9c50988e..c91d9be1 100644 --- a/object_manager.go +++ b/object_manager.go @@ -132,6 +132,9 @@ var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr * if err != nil { return nil, err } + if newVal == nil || len(newVal) == 0 { + return nil, NewNotFoundError("record not found") + } res = newVal return res, err }, @@ -151,6 +154,9 @@ var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr * if err != nil { return nil, err } + if newVal == nil || len(newVal) == 0 { + return nil, NewNotFoundError("record not found") + } res = newVal return res, err }, @@ -169,6 +175,9 @@ var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr * if err != nil { return nil, err } + if newVal == nil || len(newVal) == 0 { + return nil, NewNotFoundError("record not found") + } res = newVal return res, err }, @@ -187,6 +196,9 @@ var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr * if err != nil { return nil, err } + if newVal == nil || len(newVal) == 0 { + return nil, NewNotFoundError("record not found") + } res = newVal return res, err From 54960a0f461f5b372dc8bb9aa510b077339ffa62 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Fri, 23 Feb 2024 15:22:06 +0530 Subject: [PATCH 04/13] Return response when object is received. --- object_manager.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/object_manager.go b/object_manager.go index c91d9be1..df27bd53 100644 --- a/object_manager.go +++ b/object_manager.go @@ -445,6 +445,9 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( return nil, err } } + if res != nil { + return res, nil + } } sf := map[string]string{ From 486fcb9167f628b65637b867291cc8f0c6b35002 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Fri, 23 Feb 2024 15:43:55 +0530 Subject: [PATCH 05/13] Additional Point for existing Customer: If no Internal ID exist then don't go for EA Search and always search with Ref and get back second search only works if NotFound by ref and InternalID is present. --- object_manager.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/object_manager.go b/object_manager.go index df27bd53..65483f06 100644 --- a/object_manager.go +++ b/object_manager.go @@ -425,22 +425,20 @@ func (objMgr *ObjectManager) DeleteZoneDelegated(ref string) (string, error) { // Generic function to search object by alternate id func (objMgr *ObjectManager) SearchDnsObjectByAltId( objType string, ref string, internalId string, eaNameForInternalId string) (interface{}, error) { - var err error - if internalId == "" { - return nil, fmt.Errorf("internal ID must not be empty") - } + var ( + err error + recordType IBObject + res interface{} + ) - var recordType IBObject if getRecordTypeMap[objType] != nil { recordType = getRecordTypeMap[objType]() } else { return nil, fmt.Errorf("unknown record type") } - var res interface{} if ref != "" { if err := objMgr.connector.GetObject(recordType, ref, NewQueryParams(false, nil), &res); err != nil { - fmt.Println("Error ", err.Error()) if _, ok := err.(*NotFoundError); !ok { return nil, err } @@ -450,6 +448,10 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( } } + if internalId == "" { + return nil, err + } + sf := map[string]string{ fmt.Sprintf("*%s", eaNameForInternalId): internalId, } From b34672cbaf5045af016a59f5862061640632d6b5 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Mon, 26 Feb 2024 16:31:55 +0530 Subject: [PATCH 06/13] - Added constants - Added more records - Reduced multiple map lookups. --- object_manager.go | 167 +++++++++++++++++++++++++++------------------- 1 file changed, 98 insertions(+), 69 deletions(-) diff --git a/object_manager.go b/object_manager.go index 65483f06..6c57c17a 100644 --- a/object_manager.go +++ b/object_manager.go @@ -98,110 +98,143 @@ type IBObjectManager interface { UpdateDhcpStatus(ref string, status bool) (Dhcp, error) } +const ( + ARecord = "A" + AaaaRecord = "AAAA" + CnameRecord = "CNAME" + MxRecord = "MX" + SrvRecord = "SRV" + TxtRecord = "TXT" + PtrRecord = "PTR" + HostRecordConst = "Host" +) + // Map of record type to its corresponding object var getRecordTypeMap = map[string]func() IBObject{ - "A": func() IBObject { + ARecord: func() IBObject { return NewEmptyRecordA() }, - "AAAA": func() IBObject { + AaaaRecord: func() IBObject { return NewEmptyRecordAAAA() }, - "CNAME": func() IBObject { + CnameRecord: func() IBObject { return NewEmptyRecordCNAME() }, - "MX": func() IBObject { + MxRecord: func() IBObject { return NewEmptyRecordMX() }, + SrvRecord: func() IBObject { + return NewEmptyRecordSRV() + }, + TxtRecord: func() IBObject { + return NewEmptyRecordTXT() + }, + PtrRecord: func() IBObject { + return NewEmptyRecordPTR() + }, + HostRecordConst: func() IBObject { + return NewEmptyHostRecord() + }, } // Map returns the object with search fields with the given record type var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error){ - "A": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + ARecord: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { var res interface{} if recordType.(*RecordA).Ref != "" { return res, nil } - - err := objMgr.connector.GetObject(NewEmptyRecordA(), "", NewQueryParams(false, sf), &res) - var newVal []RecordA - byteVal, err := json.Marshal(res) - if err != nil { - return nil, err + var recordAList []*RecordA + err := objMgr.connector.GetObject(NewEmptyRecordA(), "", NewQueryParams(false, sf), &recordAList) + if err == nil && len(recordAList) > 0 { + res = recordAList[0] } - err = json.Unmarshal(byteVal, &newVal) - if err != nil { - return nil, err + return res, err + }, + AaaaRecord: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*RecordAAAA).Ref != "" { + return res, nil } - if newVal == nil || len(newVal) == 0 { - return nil, NewNotFoundError("record not found") + var recordAaaList []*RecordAAAA + err := objMgr.connector.GetObject(NewEmptyRecordAAAA(), "", NewQueryParams(false, sf), &recordAaaList) + if err == nil && len(recordAaaList) > 0 { + res = recordAaaList[0] } - res = newVal return res, err }, - "AAAA": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + CnameRecord: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { var res interface{} - if recordType.(*RecordAAAA).Ref != "" { + if recordType.(*RecordCNAME).Ref != "" { return res, nil } - - err := objMgr.connector.GetObject(NewEmptyRecordAAAA(), "", NewQueryParams(false, sf), &res) - var newVal []RecordAAAA - byteVal, err := json.Marshal(res) - if err != nil { - return nil, err + var cNameList []*RecordCNAME + err := objMgr.connector.GetObject(NewEmptyRecordCNAME(), "", NewQueryParams(false, sf), &cNameList) + if err == nil && len(cNameList) > 0 { + res = cNameList[0] } - err = json.Unmarshal(byteVal, &newVal) - if err != nil { - return nil, err + return res, err + }, + MxRecord: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*RecordMX).Ref != "" { + return res, nil } - if newVal == nil || len(newVal) == 0 { - return nil, NewNotFoundError("record not found") + var mxList []*RecordMX + err := objMgr.connector.GetObject(NewEmptyRecordMX(), "", NewQueryParams(false, sf), &mxList) + if err == nil && len(mxList) > 0 { + res = mxList[0] } - res = newVal return res, err + }, - "CNAME": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + SrvRecord: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { var res interface{} - if recordType.(*RecordCNAME).Ref != "" { + if recordType.(*RecordSRV).Ref != "" { return res, nil } - err := objMgr.connector.GetObject(NewEmptyRecordCNAME(), "", NewQueryParams(false, sf), &res) - var newVal []RecordCNAME - byteVal, err := json.Marshal(res) - if err != nil { - return nil, err + var srvList []*RecordSRV + err := objMgr.connector.GetObject(NewEmptyRecordSRV(), "", NewQueryParams(false, sf), &srvList) + if err == nil && len(srvList) > 0 { + res = srvList[0] } - err = json.Unmarshal(byteVal, &newVal) - if err != nil { - return nil, err + return res, err + }, + TxtRecord: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*RecordTXT).Ref != "" { + return res, nil } - if newVal == nil || len(newVal) == 0 { - return nil, NewNotFoundError("record not found") + var txtList []*RecordTXT + err := objMgr.connector.GetObject(NewEmptyRecordTXT(), "", NewQueryParams(false, sf), &txtList) + if err == nil && len(txtList) > 0 { + res = txtList[0] } - res = newVal return res, err }, - "MX": func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + PtrRecord: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { var res interface{} - if recordType.(*RecordMX).Ref != "" { + if recordType.(*RecordPTR).Ref != "" { return res, nil } - err := objMgr.connector.GetObject(NewEmptyRecordMX(), "", NewQueryParams(false, sf), &res) - var newVal []RecordMX - byteVal, err := json.Marshal(res) - if err != nil { - return nil, err + var ptrList []*RecordPTR + err := objMgr.connector.GetObject(NewEmptyRecordPTR(), "", NewQueryParams(false, sf), &ptrList) + if err == nil && len(ptrList) > 0 { + res = ptrList[0] } - err = json.Unmarshal(byteVal, &newVal) - if err != nil { - return nil, err + return res, err + }, + HostRecordConst: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*HostRecord).Ref != "" { + return res, nil } - if newVal == nil || len(newVal) == 0 { - return nil, NewNotFoundError("record not found") + var hostRecordList []*HostRecord + err := objMgr.connector.GetObject(NewEmptyHostRecord(), "", NewQueryParams(false, sf), &hostRecordList) + if err == nil && len(hostRecordList) > 0 { + res = hostRecordList[0] } - res = newVal return res, err - }, } @@ -430,12 +463,11 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( recordType IBObject res interface{} ) - - if getRecordTypeMap[objType] != nil { - recordType = getRecordTypeMap[objType]() - } else { + val, ok := getRecordTypeMap[objType] + if !ok { return nil, fmt.Errorf("unknown record type") } + recordType = val() if ref != "" { if err := objMgr.connector.GetObject(recordType, ref, NewQueryParams(false, nil), &res); err != nil { @@ -457,20 +489,17 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( } // Fetch the object by search fields - if getObjectWithSearchFieldsMap[objType] != nil { - res, err = getObjectWithSearchFieldsMap[objType](recordType, objMgr, sf) - } else { + getObjectWithSearchFields, ok := getObjectWithSearchFieldsMap[objType] + if !ok { return nil, fmt.Errorf("unknown record type") } - + res, err = getObjectWithSearchFields(recordType, objMgr, sf) if err != nil { return nil, err } - if res == nil { return nil, NewNotFoundError("record not found") } - result := res - return &result, nil + return &res, nil } From d044ce3dc5fe09a3d76cef6693de6128c71666cf Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Tue, 27 Feb 2024 19:33:48 +0530 Subject: [PATCH 07/13] Added support for objects(Network, Network View, auth_zone, Network Container, DNS View). --- object_manager.go | 122 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 18 deletions(-) diff --git a/object_manager.go b/object_manager.go index 6c57c17a..955fbe94 100644 --- a/object_manager.go +++ b/object_manager.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "regexp" ) // Compile-time interface checks @@ -99,42 +100,64 @@ type IBObjectManager interface { } const ( - ARecord = "A" - AaaaRecord = "AAAA" - CnameRecord = "CNAME" - MxRecord = "MX" - SrvRecord = "SRV" - TxtRecord = "TXT" - PtrRecord = "PTR" - HostRecordConst = "Host" + ARecord = "A" + AaaaRecord = "AAAA" + CnameRecord = "CNAME" + MxRecord = "MX" + SrvRecord = "SRV" + TxtRecord = "TXT" + PtrRecord = "PTR" + HostRecordConst = "Host" + DnsViewConst = "DNSView" + ZoneAuthConst = "ZoneAuth" + NetworkViewConst = "NetworkView" + NetworkConst = "Network" + NetworkContainerConst = "NetworkContainer" ) // Map of record type to its corresponding object -var getRecordTypeMap = map[string]func() IBObject{ - ARecord: func() IBObject { +var getRecordTypeMap = map[string]func(ref string) IBObject{ + ARecord: func(ref string) IBObject { return NewEmptyRecordA() }, - AaaaRecord: func() IBObject { + AaaaRecord: func(ref string) IBObject { return NewEmptyRecordAAAA() }, - CnameRecord: func() IBObject { + CnameRecord: func(ref string) IBObject { return NewEmptyRecordCNAME() }, - MxRecord: func() IBObject { + MxRecord: func(ref string) IBObject { return NewEmptyRecordMX() }, - SrvRecord: func() IBObject { + SrvRecord: func(ref string) IBObject { return NewEmptyRecordSRV() }, - TxtRecord: func() IBObject { + TxtRecord: func(ref string) IBObject { return NewEmptyRecordTXT() }, - PtrRecord: func() IBObject { + PtrRecord: func(ref string) IBObject { return NewEmptyRecordPTR() }, - HostRecordConst: func() IBObject { + HostRecordConst: func(ref string) IBObject { return NewEmptyHostRecord() }, + DnsViewConst: func(ref string) IBObject { + return NewEmptyDNSView() + }, + ZoneAuthConst: func(ref string) IBObject { + return NewZoneAuth(ZoneAuth{}) + }, + NetworkViewConst: func(ref string) IBObject { + return NewEmptyNetworkView() + }, + NetworkContainerConst: func(ref string) IBObject { + return NewNetworkContainer("", "", false, "", nil) + }, + NetworkConst: func(ref string) IBObject { + r := regexp.MustCompile("^ipv6network\\/.+") + isIPv6 := r.MatchString(ref) + return NewNetwork("", "", isIPv6, "", nil) + }, } // Map returns the object with search fields with the given record type @@ -236,6 +259,69 @@ var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr * } return res, err }, + DnsViewConst: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*View).Ref != "" { + return res, nil + } + var dnsViewList []*View + err := objMgr.connector.GetObject(NewEmptyDNSView(), "", NewQueryParams(false, sf), &dnsViewList) + if err == nil && len(dnsViewList) > 0 { + res = dnsViewList[0] + } + return res, err + }, + ZoneAuthConst: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*ZoneAuth).Ref != "" { + return res, nil + } + var zoneAuthList []*ZoneAuth + err := objMgr.connector.GetObject(NewZoneAuth(ZoneAuth{}), "", NewQueryParams(false, sf), &zoneAuthList) + if err == nil && len(zoneAuthList) > 0 { + res = zoneAuthList[0] + } + return res, err + }, + NetworkViewConst: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*NetworkView).Ref != "" { + return res, nil + } + var networkViewList []*NetworkView + err := objMgr.connector.GetObject(NewEmptyNetworkView(), "", NewQueryParams(false, sf), &networkViewList) + if err == nil && len(networkViewList) > 0 { + res = networkViewList[0] + } + return res, err + }, + // TODO: Do we need to add netview string, cidr string, isIPv6 bool, ea EA to create network container + NetworkContainerConst: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*NetworkContainer).Ref != "" { + return res, nil + } + var networkContainerList []*NetworkContainer + err := objMgr.connector.GetObject(NewNetworkContainer("", "", false, "", nil), "", NewQueryParams(false, sf), &networkContainerList) + if err == nil && len(networkContainerList) > 0 { + res = networkContainerList[0] + } + return res, err + + }, + //TODO: Do we need to add netview string, cidr string, isIPv6 bool, ea EA to create network + NetworkConst: func(recordType IBObject, objMgr *ObjectManager, sf map[string]string) (interface{}, error) { + var res interface{} + if recordType.(*Network).Ref != "" { + return res, nil + } + var networkList []*Network + err := objMgr.connector.GetObject(NewNetwork("", "", false, "", nil), "", NewQueryParams(false, sf), &networkList) + if err == nil && len(networkList) > 0 { + res = networkList[0] + } + return res, err + }, } type ObjectManager struct { @@ -467,7 +553,7 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( if !ok { return nil, fmt.Errorf("unknown record type") } - recordType = val() + recordType = val(ref) if ref != "" { if err := objMgr.connector.GetObject(recordType, ref, NewQueryParams(false, nil), &res); err != nil { From a2f801fff331951a41b27a8ec219f222a0530e62 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Fri, 1 Mar 2024 11:22:40 +0530 Subject: [PATCH 08/13] Added comparison for the fetched internal id from the response by ref with the provided internal id. --- object_manager.go | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/object_manager.go b/object_manager.go index 955fbe94..a30f50e8 100644 --- a/object_manager.go +++ b/object_manager.go @@ -561,7 +561,10 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( return nil, err } } - if res != nil { + success, err := validateObjByRef(res, internalId, eaNameForInternalId) + if err != nil { + return nil, err + } else if success { return res, nil } } @@ -589,3 +592,28 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( return &res, nil } + +func validateObjByRef(res interface{}, internalId, eaNameForInternalId string) (bool, error) { + var success bool + if res == nil { + return success, nil + } + byteObj, err := json.Marshal(res) + if err != nil { + return success, fmt.Errorf("error marshaling JSON: %v", err) + } + obj := make(map[string]interface{}) + err = json.Unmarshal(byteObj, &obj) + if err != nil { + return success, fmt.Errorf("error unmarshaling JSON: %v", err) + } + extAttrs, found := obj["extattrs"].(map[string]interface{}) + if found { + resInternalId := extAttrs[eaNameForInternalId].(map[string]interface{})["value"] + if resInternalId != nil && resInternalId.(string) == internalId { + success = true + return success, nil + } + } + return success, nil +} From 78a681b7130c87e9ebd996db3f7e03181ed71d76 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Tue, 5 Mar 2024 15:30:57 +0530 Subject: [PATCH 09/13] Moved the empty internal id check before the validation of the fetched object with the given internal id. --- object_manager.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/object_manager.go b/object_manager.go index a30f50e8..25f68d4f 100644 --- a/object_manager.go +++ b/object_manager.go @@ -78,7 +78,7 @@ type IBObjectManager interface { GetAllMembers() ([]Member, error) GetGridInfo() ([]Grid, error) GetGridLicense() ([]License, error) - SearchDnsObjectByAltId(objType string, internalId string, ref string, eaNameForInternalId string) (interface{}, error) + SearchObjectByAltId(objType string, internalId string, ref string, eaNameForInternalId string) (interface{}, error) ReleaseIP(netview string, cidr string, ipAddr string, isIPv6 bool, macAddr string) (string, error) UpdateAAAARecord(ref string, netView string, recordName string, cidr string, ipAddr string, useTtl bool, ttl uint32, comment string, setEas EA) (*RecordAAAA, error) UpdateCNAMERecord(ref string, canonical string, recordName string, useTtl bool, ttl uint32, comment string, setEas EA) (*RecordCNAME, error) @@ -541,8 +541,8 @@ func (objMgr *ObjectManager) DeleteZoneDelegated(ref string) (string, error) { return objMgr.connector.DeleteObject(ref) } -// Generic function to search object by alternate id -func (objMgr *ObjectManager) SearchDnsObjectByAltId( +// SearchObjectByAltId is a generic function to search object by alternate id +func (objMgr *ObjectManager) SearchObjectByAltId( objType string, ref string, internalId string, eaNameForInternalId string) (interface{}, error) { var ( err error @@ -556,12 +556,13 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( recordType = val(ref) if ref != "" { + // Fetching object by reference if err := objMgr.connector.GetObject(recordType, ref, NewQueryParams(false, nil), &res); err != nil { - if _, ok := err.(*NotFoundError); !ok { + if _, ok := err.(*NotFoundError); !ok || internalId == "" { return nil, err } } - success, err := validateObjByRef(res, internalId, eaNameForInternalId) + success, err := validateObjByInternalId(res, internalId, eaNameForInternalId) if err != nil { return nil, err } else if success { @@ -569,10 +570,6 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( } } - if internalId == "" { - return nil, err - } - sf := map[string]string{ fmt.Sprintf("*%s", eaNameForInternalId): internalId, } @@ -593,7 +590,8 @@ func (objMgr *ObjectManager) SearchDnsObjectByAltId( return &res, nil } -func validateObjByRef(res interface{}, internalId, eaNameForInternalId string) (bool, error) { +// validateObjByInternalId validates the object by comparing the given internal with the object's internal id +func validateObjByInternalId(res interface{}, internalId, eaNameForInternalId string) (bool, error) { var success bool if res == nil { return success, nil From ab8b65cae3835c758c711fef1101b42f3de7ad71 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Wed, 6 Mar 2024 14:56:53 +0530 Subject: [PATCH 10/13] Updated the internal id check. --- object_manager.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/object_manager.go b/object_manager.go index 25f68d4f..e0711055 100644 --- a/object_manager.go +++ b/object_manager.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "regexp" + "strings" ) // Compile-time interface checks @@ -558,7 +559,7 @@ func (objMgr *ObjectManager) SearchObjectByAltId( if ref != "" { // Fetching object by reference if err := objMgr.connector.GetObject(recordType, ref, NewQueryParams(false, nil), &res); err != nil { - if _, ok := err.(*NotFoundError); !ok || internalId == "" { + if _, ok := err.(*NotFoundError); !ok { return nil, err } } @@ -593,7 +594,7 @@ func (objMgr *ObjectManager) SearchObjectByAltId( // validateObjByInternalId validates the object by comparing the given internal with the object's internal id func validateObjByInternalId(res interface{}, internalId, eaNameForInternalId string) (bool, error) { var success bool - if res == nil { + if res == nil || strings.TrimSpace(internalId) == "" { return success, nil } byteObj, err := json.Marshal(res) From 89dca1677d4d0d71feae35af871ca5ab64486384 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Wed, 6 Mar 2024 15:39:20 +0530 Subject: [PATCH 11/13] Optimised the func validateObjByInternalId. --- object_manager.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/object_manager.go b/object_manager.go index e0711055..1e4885a1 100644 --- a/object_manager.go +++ b/object_manager.go @@ -606,13 +606,22 @@ func validateObjByInternalId(res interface{}, internalId, eaNameForInternalId st if err != nil { return success, fmt.Errorf("error unmarshaling JSON: %v", err) } - extAttrs, found := obj["extattrs"].(map[string]interface{}) - if found { - resInternalId := extAttrs[eaNameForInternalId].(map[string]interface{})["value"] - if resInternalId != nil && resInternalId.(string) == internalId { + extAttrs, err := getInterfaceValueFromMap(obj, "extattrs") + if err != nil { + resInternalId, err := getInterfaceValueFromMap(extAttrs, eaNameForInternalId) + if err != nil && resInternalId["value"] != nil && resInternalId["value"].(string) == internalId { success = true return success, nil } } return success, nil } + +// getInterfaceValueFromMap returns the value, after converting it into a map[string]interface{}, of the given key from the map +func getInterfaceValueFromMap(m map[string]interface{}, key string) (map[string]interface{}, error) { + if val, ok := m[key]; ok && val != nil { + res := val.(map[string]interface{}) + return res, nil + } + return nil, fmt.Errorf("key %s not found in map", key) +} From f3cce512d207c6c13c8956ca7e6ca299486b3565 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Thu, 7 Mar 2024 11:43:12 +0530 Subject: [PATCH 12/13] Added another scenario where we would return the objectByRef if the internal id is missing. --- object_manager.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/object_manager.go b/object_manager.go index 1e4885a1..e82dd783 100644 --- a/object_manager.go +++ b/object_manager.go @@ -594,7 +594,11 @@ func (objMgr *ObjectManager) SearchObjectByAltId( // validateObjByInternalId validates the object by comparing the given internal with the object's internal id func validateObjByInternalId(res interface{}, internalId, eaNameForInternalId string) (bool, error) { var success bool - if res == nil || strings.TrimSpace(internalId) == "" { + if res == nil { + return success, nil + } else if strings.TrimSpace(internalId) == "" { + // return object if internal id is empty + success = true return success, nil } byteObj, err := json.Marshal(res) @@ -607,14 +611,16 @@ func validateObjByInternalId(res interface{}, internalId, eaNameForInternalId st return success, fmt.Errorf("error unmarshaling JSON: %v", err) } extAttrs, err := getInterfaceValueFromMap(obj, "extattrs") - if err != nil { + if err == nil { resInternalId, err := getInterfaceValueFromMap(extAttrs, eaNameForInternalId) - if err != nil && resInternalId["value"] != nil && resInternalId["value"].(string) == internalId { + if err == nil && resInternalId["value"] != nil && resInternalId["value"].(string) == internalId { + // return object if object's internal id matches with the given internal id success = true return success, nil } + return success, err } - return success, nil + return success, err } // getInterfaceValueFromMap returns the value, after converting it into a map[string]interface{}, of the given key from the map From a3bbb89674ee0ea6669e6e3d72f553e5526c1be9 Mon Sep 17 00:00:00 2001 From: Sudarshan Das Date: Mon, 11 Mar 2024 12:19:55 +0530 Subject: [PATCH 13/13] Added return fields to zoneAuth object. --- object_manager.go | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/object_manager.go b/object_manager.go index e82dd783..9bfba360 100644 --- a/object_manager.go +++ b/object_manager.go @@ -146,7 +146,21 @@ var getRecordTypeMap = map[string]func(ref string) IBObject{ return NewEmptyDNSView() }, ZoneAuthConst: func(ref string) IBObject { - return NewZoneAuth(ZoneAuth{}) + zone := &ZoneAuth{} + zone.SetReturnFields(append( + zone.ReturnFields(), + "comment", + "ns_group", + "soa_default_ttl", + "soa_expire", + "soa_negative_ttl", + "soa_refresh", + "soa_retry", + "view", + "zone_format", + "extattrs", + )) + return zone }, NetworkViewConst: func(ref string) IBObject { return NewEmptyNetworkView() @@ -277,8 +291,9 @@ var getObjectWithSearchFieldsMap = map[string]func(recordType IBObject, objMgr * if recordType.(*ZoneAuth).Ref != "" { return res, nil } + zoneAuth := recordType.(*ZoneAuth) var zoneAuthList []*ZoneAuth - err := objMgr.connector.GetObject(NewZoneAuth(ZoneAuth{}), "", NewQueryParams(false, sf), &zoneAuthList) + err := objMgr.connector.GetObject(zoneAuth, "", NewQueryParams(false, sf), &zoneAuthList) if err == nil && len(zoneAuthList) > 0 { res = zoneAuthList[0] }