@@ -352,7 +352,6 @@ def get_config_replace(self, node_self, node_other):
352
352
353
353
for child_other in in_o_not_in_s :
354
354
child_self = etree .Element (child_other .tag ,
355
- {operation_tag : self .preferred_delete },
356
355
nsmap = child_other .nsmap )
357
356
siblings = list (node_self .iterchildren (tag = child_other .tag ))
358
357
if siblings :
@@ -361,14 +360,24 @@ def get_config_replace(self, node_self, node_other):
361
360
node_self .append (child_self )
362
361
s_node = self .device .get_schema_node (child_other )
363
362
if s_node .get ('type' ) == 'leaf-list' :
363
+ child_self .set (operation_tag , self .preferred_delete )
364
364
self ._merge_text (child_other , child_self )
365
365
elif s_node .get ('type' ) == 'list' :
366
+ child_self .set (operation_tag , self .preferred_delete )
366
367
keys = self ._get_list_keys (s_node )
367
368
for key in keys :
368
369
key_node = child_other .find (key )
369
370
e = etree .SubElement (
370
371
child_self , key , nsmap = key_node .nsmap )
371
372
e .text = key_node .text
373
+ elif (
374
+ s_node .get ('type' ) == 'container' and
375
+ s_node .get ('presence' ) != 'true' and
376
+ self .preferred_delete == 'delete'
377
+ ):
378
+ self .set_delete_operation (child_self , child_other )
379
+ else :
380
+ child_self .set (operation_tag , self .preferred_delete )
372
381
373
382
for child_self , child_other in in_s_and_in_o :
374
383
child_self .set (operation_tag , 'replace' )
@@ -1066,7 +1075,6 @@ def node_sub(self, node_self, node_other, depth=0):
1066
1075
choice_nodes = {}
1067
1076
for child_self in in_s_not_in_o :
1068
1077
child_other = etree .Element (child_self .tag ,
1069
- {operation_tag : self .preferred_delete },
1070
1078
nsmap = child_self .nsmap )
1071
1079
if self .diff_type == 'replace' :
1072
1080
child_self .set (operation_tag , 'replace' )
@@ -1084,8 +1092,10 @@ def node_sub(self, node_self, node_other, depth=0):
1084
1092
if s_node .get ('ordered-by' ) == 'user' and \
1085
1093
s_node .tag not in ordered_by_user :
1086
1094
ordered_by_user [s_node .tag ] = 'leaf-list'
1095
+ child_other .set (operation_tag , self .preferred_delete )
1087
1096
self ._merge_text (child_self , child_other )
1088
1097
elif s_node .get ('type' ) == 'list' :
1098
+ child_other .set (operation_tag , self .preferred_delete )
1089
1099
keys = self ._get_list_keys (s_node )
1090
1100
if s_node .get ('ordered-by' ) == 'user' and \
1091
1101
s_node .tag not in ordered_by_user :
@@ -1095,12 +1105,19 @@ def node_sub(self, node_self, node_other, depth=0):
1095
1105
e = etree .SubElement (
1096
1106
child_other , key , nsmap = key_node .nsmap )
1097
1107
e .text = key_node .text
1108
+ elif (
1109
+ s_node .get ('type' ) == 'container' and
1110
+ s_node .get ('presence' ) != 'true' and
1111
+ self .preferred_delete == 'delete'
1112
+ ):
1113
+ self .set_delete_operation (child_other , child_self )
1114
+ else :
1115
+ child_other .set (operation_tag , self .preferred_delete )
1098
1116
if s_node .getparent ().get ('type' ) == 'case' :
1099
1117
# key: choice node, value: case node
1100
1118
choice_nodes [s_node .getparent ().getparent ()] = s_node .getparent ()
1101
1119
for child_other in in_o_not_in_s :
1102
1120
child_self = etree .Element (child_other .tag ,
1103
- {operation_tag : self .preferred_delete },
1104
1121
nsmap = child_other .nsmap )
1105
1122
if self .preferred_create == 'replace' :
1106
1123
child_other .set (operation_tag , self .preferred_create )
@@ -1126,8 +1143,10 @@ def node_sub(self, node_self, node_other, depth=0):
1126
1143
if s_node .get ('ordered-by' ) == 'user' and \
1127
1144
s_node .tag not in ordered_by_user :
1128
1145
ordered_by_user [s_node .tag ] = 'leaf-list'
1146
+ child_self .set (operation_tag , self .preferred_delete )
1129
1147
self ._merge_text (child_other , child_self )
1130
1148
elif s_node .get ('type' ) == 'list' :
1149
+ child_self .set (operation_tag , self .preferred_delete )
1131
1150
keys = self ._get_list_keys (s_node )
1132
1151
if s_node .get ('ordered-by' ) == 'user' and \
1133
1152
s_node .tag not in ordered_by_user :
@@ -1136,6 +1155,14 @@ def node_sub(self, node_self, node_other, depth=0):
1136
1155
key_node = child_other .find (key )
1137
1156
e = etree .SubElement (child_self , key , nsmap = key_node .nsmap )
1138
1157
e .text = key_node .text
1158
+ elif (
1159
+ s_node .get ('type' ) == 'container' and
1160
+ s_node .get ('presence' ) != 'true' and
1161
+ self .preferred_delete == 'delete'
1162
+ ):
1163
+ self .set_delete_operation (child_self , child_other )
1164
+ else :
1165
+ child_self .set (operation_tag , self .preferred_delete )
1139
1166
for child_self , child_other in in_s_and_in_o :
1140
1167
s_node = self .device .get_schema_node (child_self )
1141
1168
if s_node .get ('type' ) == 'leaf' :
@@ -1246,16 +1273,74 @@ def set_create_operation(self, node):
1246
1273
'''
1247
1274
1248
1275
schema_node = self .device .get_schema_node (node )
1276
+
1277
+ # Create operation on non-presence containers is not allowed as per
1278
+ # ConfD implementation although the expected behavior is ambiguous in
1279
+ # RFC7950. More discussion can be found in the Tail-F ticket PS-47089.
1249
1280
if (
1250
1281
schema_node .get ('type' ) == 'container' and
1251
- schema_node .get ('presence' ) != 'true' and
1252
- len (self .device .default_in_use (schema_node )) > 0
1282
+ schema_node .get ('presence' ) != 'true'
1253
1283
):
1284
+ default_xpaths = [self .device .get_xpath (n )
1285
+ for n in self .device .default_in_use (schema_node )]
1254
1286
for child in node :
1255
- self .set_create_operation (child )
1287
+ child_xpath = self .device .get_xpath (
1288
+ self .device .get_schema_node (child ))
1289
+ if child_xpath not in default_xpaths :
1290
+ self .set_create_operation (child )
1256
1291
else :
1257
1292
node .set (operation_tag , 'create' )
1258
1293
1294
+ def set_delete_operation (self , node , reference_node ):
1295
+ '''set_delete_operation
1296
+ Low-level api: Set the `operation` attribute of a node to `delete` when
1297
+ it is not already set. This method is used when the preferred_delete is
1298
+ `delete`.
1299
+ Parameters
1300
+ ----------
1301
+ node : `Element`
1302
+ A config node in a config tree. `delete` operation will be set on
1303
+ descendants of this node.
1304
+ reference_node : `Element`
1305
+ A config node in a config tree as a reference when building the
1306
+ input parameter `node`. This node has descendants that `node` does
1307
+ not have.
1308
+ Returns
1309
+ -------
1310
+ None
1311
+ There is no return of this method.
1312
+ '''
1313
+
1314
+ # Delete operation on non-presence containers is allowed even there is
1315
+ # nothing inside the non-presence container as per ConfD implementation
1316
+ # although the expected behavior is ambiguous in RFC7950. More
1317
+ # discussion can be found in the Tail-F ticket PS-47089. In negative
1318
+ # testing case, if we want the delete operation to be rejected when
1319
+ # there is nothing inside the non-presence container, we have to put
1320
+ # delete operations on the descendants of the non-presence container,
1321
+ # which are not non-presence containers.
1322
+ for reference_child in reference_node :
1323
+ child = etree .SubElement (node , reference_child .tag ,
1324
+ nsmap = reference_child .nsmap )
1325
+ schema_node = self .device .get_schema_node (reference_child )
1326
+ if schema_node .get ('type' ) == 'leaf-list' :
1327
+ child .set (operation_tag , 'delete' )
1328
+ self ._merge_text (reference_child , child )
1329
+ elif schema_node .get ('type' ) == 'list' :
1330
+ child .set (operation_tag , 'delete' )
1331
+ keys = self ._get_list_keys (schema_node )
1332
+ for key in keys :
1333
+ key_node = reference_child .find (key )
1334
+ e = etree .SubElement (child , key , nsmap = key_node .nsmap )
1335
+ e .text = key_node .text
1336
+ elif (
1337
+ schema_node .get ('type' ) == 'container' and
1338
+ schema_node .get ('presence' ) != 'true'
1339
+ ):
1340
+ self .set_delete_operation (child , reference_child )
1341
+ else :
1342
+ child .set (operation_tag , 'delete' )
1343
+
1259
1344
@staticmethod
1260
1345
def _url_to_prefix (node , id ):
1261
1346
'''_url_to_prefix
0 commit comments