Skip to content

Commit c65cc4a

Browse files
authored
Merge branch 'master' into oc-intf-upgrade_new-leaves-support_bug-fixes
2 parents c1752df + bb0e47d commit c65cc4a

File tree

13 files changed

+1900
-199
lines changed

13 files changed

+1900
-199
lines changed

models/yang/extensions/openconfig-sampling-sflow-deviation.yang

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ module openconfig-sampling-sflow-deviation {
4848
deviate not-supported;
4949
}
5050

51+
deviation /oc-sampling:sampling/oc-sampling:sflow/oc-sampling:state/oc-sampling:sampling-rate {
52+
deviate not-supported;
53+
}
54+
5155
deviation /oc-sampling:sampling/oc-sampling:sflow/oc-sampling:collectors/oc-sampling:collector/oc-sampling:state/oc-sampling:packets-sent {
5256
deviate not-supported;
5357
}

translib/common_app.go

Lines changed: 261 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,12 @@ func (app *CommonApp) cmnAppCRUCommonDbOpn(d *db.DB, opcode int, dbMap map[strin
740740
A leaf-list field in redis has "@" suffix as per swsssdk convention.
741741
*/
742742
resTblRw := db.Value{Field: map[string]string{}}
743-
resTblRw = checkAndProcessLeafList(existingEntry, tblRw, UPDATE, d, tblNm, tblKey)
743+
/* for north-bound REPLACE request always swap the whole leaf-list */
744+
if app.cmnAppOpcode == REPLACE {
745+
resTblRw = tblRw
746+
} else {
747+
resTblRw = checkAndProcessLeafList(existingEntry, tblRw, UPDATE, d, tblNm, tblKey)
748+
}
744749
log.Info("Processing Table row ", resTblRw)
745750
err = d.ModEntry(cmnAppTs, db.Key{Comp: []string{tblKey}}, resTblRw)
746751
if err != nil {
@@ -773,7 +778,12 @@ func (app *CommonApp) cmnAppCRUCommonDbOpn(d *db.DB, opcode int, dbMap map[strin
773778
A leaf-list field in redis has "@" suffix as per swsssdk convention.
774779
*/
775780
resTblRw := db.Value{Field: map[string]string{}}
776-
resTblRw = checkAndProcessLeafList(existingEntry, tblRw, UPDATE, d, tblNm, tblKey)
781+
/* for north-bound REPLACE request always swap the whole leaf-list */
782+
if app.cmnAppOpcode == REPLACE {
783+
resTblRw = tblRw
784+
} else {
785+
resTblRw = checkAndProcessLeafList(existingEntry, tblRw, UPDATE, d, tblNm, tblKey)
786+
}
777787
err = d.ModEntry(cmnAppTs, db.Key{Comp: []string{tblKey}}, resTblRw)
778788
if err != nil {
779789
log.Warning("UPDATE case - d.ModEntry() failure")
@@ -929,18 +939,195 @@ func deleteFields(existingEntry db.Value, d *db.DB, cmnAppTs *db.TableSpec, tblK
929939
return err
930940
}
931941

942+
func (app *CommonApp) processTableDeleteForReplace(d *db.DB, parentTblNm string, parentTblSpec *db.TableSpec, moduleNm string, cvlSess *cvl.CVL, ordParentTblKeys []string) error {
943+
var err error
944+
var childTblToCleanMap map[string]bool
945+
var parentTblKeyMap map[string]db.Value
946+
var parentTblKeys []db.Key
947+
var getKeysErr error
948+
949+
replaceDbMap, replaceOk := app.cmnAppTableMap[REPLACE][db.ConfigDB]
950+
951+
/* non-table owners are filled in update by infra, subtrees can fill anywhere
952+
map-consolidation at the end of infra translation before hitting common_app
953+
should merge the data if table-instance present across operations.
954+
*/
955+
updateDbMap, updateOk := app.cmnAppTableMap[UPDATE][db.ConfigDB]
956+
createDbMap, createOk := app.cmnAppTableMap[CREATE][db.ConfigDB]
957+
if !replaceOk && !updateOk && !createOk {
958+
log.V(4).Info("No data in REPLACE, UPDATE and CREATE result map.")
959+
return nil
960+
}
961+
if len(ordParentTblKeys) == 0 {
962+
parentTblKeys, getKeysErr = d.GetKeys(parentTblSpec)
963+
if getKeysErr != nil {
964+
log.Warningf("GetKeys() failed for parent table - %v - error - %v", parentTblNm, getKeysErr)
965+
}
966+
if len(parentTblKeys) == 0 {
967+
log.V(4).Info("No DB data found so no action to take for parent table ", parentTblNm)
968+
return nil
969+
}
970+
}
971+
972+
log.Infof("processDeleteForReplace: parent table %v", parentTblNm)
973+
974+
childTblToCleanMap = make(map[string]bool)
975+
for oper, dbMap := range app.cmnAppTableMap {
976+
//table/instances passed as input param to this function belong to DELETE resultmap
977+
if (oper == DELETE) || (len(dbMap) == 0) || (len(dbMap[db.ConfigDB]) == 0) {
978+
continue
979+
}
980+
markChildTablesToCleanFromTranslatedResult(d, dbMap[db.ConfigDB], childTblToCleanMap, parentTblNm, moduleNm)
981+
if log.V(4) {
982+
log.Infof("populated child tables that might need cleanup after processing result tables for oper %v is %v", oper, childTblToCleanMap)
983+
}
984+
}
985+
986+
if len(childTblToCleanMap) == 0 {
987+
log.Info("No child tables, mapped to/under target URI yang hierarchy remaining for cleanup.")
988+
return nil
989+
}
990+
991+
if len(ordParentTblKeys) == 0 {
992+
parentTblKeyMap = make(map[string]db.Value)
993+
log.V(4).Info("parent table keys - ", parentTblKeys)
994+
for _, parentKey := range parentTblKeys {
995+
parentTblKeyMap[strings.Join(parentKey.Comp, "|")] = db.Value{}
996+
}
997+
log.V(4).Info("parent table key map - ", parentTblKeyMap)
998+
ordParentTblKeys = transformer.SortSncTableDbKeys(parentTblNm, parentTblKeyMap)
999+
}
1000+
log.V(4).Info("Sorted parent table keys - ", ordParentTblKeys)
1001+
1002+
for _, parentKey := range ordParentTblKeys {
1003+
log.V(4).Info("processing parentKey: ", parentKey)
1004+
parentInst := parentTblNm + "|" + parentKey
1005+
depDataList := cvlSess.GetDepDataForDelete(parentInst)
1006+
log.V(4).Info("depList: ", depDataList)
1007+
for idx := len(depDataList) - 1; idx >= 0; idx-- { //CVL gives in parent first order
1008+
depEntry := depDataList[idx]
1009+
log.V(4).Infof("Processing depEntry for item %v in depDataList ", depEntry.RefKey)
1010+
for depInst, depInstFieldMap := range depEntry.Entry {
1011+
log.V(4).Info("Processing depInst:depFields ", depInst, depInstFieldMap)
1012+
childTblAndKey := strings.SplitN(depInst, "|", 2)
1013+
if len(childTblAndKey) != 2 {
1014+
log.Warning("Child table/key not found in depInst: ", depInst)
1015+
continue
1016+
}
1017+
childTblNm := childTblAndKey[0]
1018+
childTblKey := childTblAndKey[1]
1019+
if !childTblToCleanMap[childTblNm] {
1020+
continue
1021+
}
1022+
1023+
/* Child table mapped in the yang hierarchy from request URI will be present either
1024+
in REPLACE/UPDATE/CREATE result-map(payload/direct map to request URI) based on
1025+
table ownership, or in DELETE result-map(since a GET like traversal is done).
1026+
If present in DELETE result-map then its already processed being a child table
1027+
and no clean-up needed before cleaning parent.Clean-up needed only when present
1028+
in REPLACE/UPDATE/CREATE
1029+
*/
1030+
tblOwner := true //if instance found in REPLACE map then table owner
1031+
nonTblOwnerInstRwInResultMap := db.Value{}
1032+
nonTblOwnerInstRwInResultMap.Field = make(map[string]string)
1033+
var instInReplaceMap, instInUpdateMap, instInCreateMap bool
1034+
if _, instInReplaceMap = replaceDbMap[childTblNm][childTblKey]; !instInReplaceMap {
1035+
if nonTblOwnerInstRwInResultMap, instInUpdateMap = updateDbMap[childTblNm][childTblKey]; !instInUpdateMap {
1036+
if nonTblOwnerInstRwInResultMap, instInCreateMap = createDbMap[childTblNm][childTblKey]; !instInCreateMap {
1037+
log.V(4).Info("Table instance not found in REPLACE/UPDATE/CREATE result map.")
1038+
continue
1039+
}
1040+
}
1041+
tblOwner = false
1042+
log.V(4).Infof("Table instance %v found in UPDATE/CREATE result map with fields %v", childTblAndKey, nonTblOwnerInstRwInResultMap)
1043+
}
1044+
1045+
//cleanup depending on table-ownership and key vs non-key based relationship between the parent and child table
1046+
childTblSpec := &db.TableSpec{Name: childTblNm}
1047+
if len(depInstFieldMap) > 0 {
1048+
// non-key based realtionship so clean-up only dependent fields
1049+
var fieldRw db.Value
1050+
fieldRw.Field = make(map[string]string)
1051+
for field, val := range depInstFieldMap {
1052+
fieldRw.Field[field] = val
1053+
}
1054+
if !tblOwner {
1055+
/* for non-table owner if dependent data has a field not mapped to/under the
1056+
target URI yang hierarchy then abort since CVL will not allow parent to be deleted
1057+
without dependency being cleaned.
1058+
*/
1059+
cleanUp, cleanUpErr := checkNonTblOwnerDepChildNeedsCleanUp(fieldRw, nonTblOwnerInstRwInResultMap,
1060+
parentInst, depInst, app.pathInfo.Path)
1061+
if cleanUpErr != nil {
1062+
return cleanUpErr
1063+
}
1064+
if !cleanUp {
1065+
continue
1066+
}
1067+
}
1068+
err = d.DeleteEntryFields(childTblSpec, db.Key{Comp: []string{childTblKey}}, fieldRw)
1069+
if err != nil {
1070+
log.Warning("DELETE for REPLACE case d.DeleteEntryFields() failure")
1071+
return err
1072+
}
1073+
} else {
1074+
//key based relation between parent and child so complete child instance can be deleted
1075+
if !tblOwner {
1076+
/* for non-table owner entire child instance cannot be deleted
1077+
if that instance in DB has a field not mapped to/under the
1078+
target URI yang hierarchy.
1079+
*/
1080+
existingEntry, existingEntryErr := d.GetEntry(childTblSpec, db.Key{Comp: []string{childTblKey}})
1081+
if existingEntryErr != nil {
1082+
log.Warning("DELETE case for REPLACE - d.GetEntry() failure")
1083+
return err
1084+
}
1085+
if existingEntry.IsPopulated() {
1086+
cleanUp, cleanUpErr := checkNonTblOwnerDepChildNeedsCleanUp(existingEntry, nonTblOwnerInstRwInResultMap,
1087+
parentInst, depInst, app.pathInfo.Path)
1088+
if cleanUpErr != nil {
1089+
return cleanUpErr
1090+
}
1091+
if !cleanUp {
1092+
continue
1093+
}
1094+
}
1095+
}
1096+
err = d.DeleteEntry(childTblSpec, db.Key{Comp: []string{childTblKey}})
1097+
if err != nil {
1098+
log.Warning("DELETE for REPLACE case - d.DeleteEntry() failure")
1099+
return err
1100+
}
1101+
}
1102+
}
1103+
} // end of depData List loop
1104+
} //end of parent table keys loop
1105+
1106+
return nil
1107+
}
1108+
9321109
func (app *CommonApp) handleChildDeleteForOcReplaceAndDelete(d *db.DB, sortedDelTblLst []string, moduleNm string) error {
9331110
/* resultTblLst has child first, parent later order */
1111+
var cvlSess *cvl.CVL
9341112
var err error
9351113

1114+
if app.cmnAppOpcode == REPLACE {
1115+
cvlSess, err = d.NewValidationSession()
1116+
if err != nil || cvlSess == nil {
1117+
log.Info("getCVLDepDataForDelete : cvl.ValidationSessOpen failed")
1118+
return err
1119+
}
1120+
defer cvl.ValidationSessClose(cvlSess)
1121+
}
1122+
9361123
for _, tblNm := range sortedDelTblLst {
9371124
log.V(4).Info("In Yang to DB map returned from transformer looking for table = ", tblNm)
9381125
var parentKeysList []string
9391126
if tblVal, ok := app.cmnAppTableMap[DELETE][db.ConfigDB][tblNm]; ok {
9401127
cmnAppTs := &db.TableSpec{Name: tblNm}
9411128
if len(tblVal) == 0 {
9421129
log.Info("No table instances/rows found hence mark entire table to be deleted = ", tblNm)
943-
/* handle child table cleanup when North Bound oper is REPLACE- TODO.
1130+
/* handle child table cleanup when North Bound oper is REPLACE
9441131
For north bound DELETE child yang hierarchy traversal for target/request
9451132
URI will populate the relevant child tables in the result map and
9461133
SortAsPerTblDeps() on the tables in result map will take care of child table getting
@@ -949,11 +1136,16 @@ func (app *CommonApp) handleChildDeleteForOcReplaceAndDelete(d *db.DB, sortedDel
9491136
*/
9501137
if app.cmnAppOpcode == REPLACE {
9511138
log.V(4).Info("process Table level Delete For North Bound Replace oper")
952-
/* TODO - For North Bound REPLACE operation payload translation can result in
1139+
/* For North Bound REPLACE operation payload translation can result in
9531140
data being populated in UPDATE map based on table ownership and also the
9541141
scope of db-mapping at the target URL.DELETE map will contain whats not present
9551142
in the payload in yang hiercharchy beneath the target URL.Thus data needs to be
956-
processed in order resolving dependencies to achieve the end result */
1143+
processed in order resolving dependencies to achieve the end result.
1144+
*/
1145+
err = app.processTableDeleteForReplace(d, tblNm, cmnAppTs, moduleNm, cvlSess, parentKeysList)
1146+
if err != nil {
1147+
return err
1148+
}
9571149
}
9581150
log.Info("deleting table = ", tblNm)
9591151
err = d.DeleteTable(cmnAppTs)
@@ -1002,7 +1194,7 @@ func (app *CommonApp) handleChildDeleteForOcReplaceAndDelete(d *db.DB, sortedDel
10021194
log.Info("Table Entry from which the fields are to be deleted does not exist. Ignore error for non existant instance for idempotency")
10031195
continue
10041196
}
1005-
if log.V(3) {
1197+
if log.V(4) {
10061198
log.Info("Fields delete", cmnAppTs, db.Key{Comp: []string{tblKey}}, tblRw)
10071199
}
10081200
err = deleteFields(existingEntry, d, cmnAppTs, tblKey, tblRw, app.deleteEmptyEntry)
@@ -1014,7 +1206,23 @@ func (app *CommonApp) handleChildDeleteForOcReplaceAndDelete(d *db.DB, sortedDel
10141206
}
10151207
/* Delete the dependent entries for all keys in parentKeysList in case of REPLACE */
10161208
if app.cmnAppOpcode == REPLACE && len(parentKeysList) > 0 {
1017-
// TODO as mentioned in above comment
1209+
err = app.processTableDeleteForReplace(d, tblNm, cmnAppTs, moduleNm, cvlSess, parentKeysList)
1210+
if err != nil {
1211+
return err
1212+
}
1213+
}
1214+
for _, tableKey := range parentKeysList {
1215+
log.V(4).Info("Delete parent entry ", cmnAppTs, db.Key{Comp: []string{tableKey}})
1216+
err = d.DeleteEntry(cmnAppTs, db.Key{Comp: []string{tableKey}})
1217+
if err != nil {
1218+
if cvl.CVLRetCode(err.(tlerr.TranslibCVLFailure).Code) == cvl.CVL_SEMANTIC_KEY_NOT_EXIST {
1219+
log.V(4).Infof("Ignore delete that cannot be processed for table %v key %v that does not exist. err %v", tblNm, tableKey, err.(tlerr.TranslibCVLFailure).CVLErrorInfo.ConstraintErrMsg)
1220+
err = nil
1221+
} else {
1222+
log.Warning("DELETE case - d.DeleteEntry() failure")
1223+
return err
1224+
}
1225+
}
10181226
}
10191227
}
10201228
}
@@ -1380,3 +1588,49 @@ func isPartialReplace(exstRw db.Value, replTblRw db.Value, auxRw db.Value) bool
13801588
log.Info("returning partialReplace - ", partialReplace)
13811589
return partialReplace
13821590
}
1591+
1592+
func checkNonTblOwnerDepChildNeedsCleanUp(entryTocheckAgainst db.Value, resultMapEntry db.Value, parentTblInst string, childTblInst string, targetPath string) (bool, error) {
1593+
foundfieldNotMapped := false
1594+
fieldNm := ""
1595+
log.Info("checkNonTblOwnerDepChildNeedsCleanUp() - entryTocheckAgainst", entryTocheckAgainst, "resultMapEntry", resultMapEntry)
1596+
for field := range entryTocheckAgainst.Field {
1597+
if !resultMapEntry.Has(field) {
1598+
foundfieldNotMapped = true
1599+
fieldNm = field
1600+
break
1601+
}
1602+
}
1603+
if foundfieldNotMapped {
1604+
fieldNm = strings.TrimSuffix(fieldNm, "@")
1605+
log.Warningf("Found field %v not mapped to/under target URI yang hierarchy in child instance %v so cannot delete the child instance.", fieldNm, childTblInst)
1606+
errStr := fmt.Sprintf("Instance %v is in use by %v for field %v(not mapped in target yang hierarchy) and cannot be deleted.", parentTblInst, childTblInst, fieldNm)
1607+
return false, tlerr.InternalError{Format: errStr, Path: targetPath}
1608+
}
1609+
1610+
return true, nil
1611+
}
1612+
1613+
func markChildTablesToCleanFromTranslatedResult(d *db.DB, resultDbMap map[string]map[string]db.Value, childTblToCleanMap map[string]bool, parentTblNm string, moduleNm string) {
1614+
for tblNm := range resultDbMap {
1615+
if tblNm == parentTblNm {
1616+
continue
1617+
}
1618+
if childTblToCleanMap[tblNm] {
1619+
log.Info("Table already marked for cleaning ", tblNm)
1620+
continue
1621+
}
1622+
tblSpec := &db.TableSpec{Name: tblNm}
1623+
tblKeys, getKeysErr := d.GetKeys(tblSpec)
1624+
if getKeysErr != nil {
1625+
log.Infof("GetKeys() failed for table - %v - error - %v", tblNm, getKeysErr)
1626+
}
1627+
if len(tblKeys) == 0 {
1628+
log.Info("No DB data found so no action to take for table ", tblNm)
1629+
continue
1630+
}
1631+
if !transformer.IsDependentChildTable(tblNm, parentTblNm, moduleNm) {
1632+
continue
1633+
}
1634+
childTblToCleanMap[tblNm] = true
1635+
}
1636+
}

0 commit comments

Comments
 (0)