Committed by
Gerrit Code Review
Add config validation for vRouter and PIM configs
Change-Id: I97ddf4f745a19df6998b15ae47ebde5aa5f46238
Showing
4 changed files
with
237 additions
and
15 deletions
... | @@ -112,4 +112,20 @@ public class PimInterfaceConfig extends Config<ConnectPoint> { | ... | @@ -112,4 +112,20 @@ public class PimInterfaceConfig extends Config<ConnectPoint> { |
112 | } | 112 | } |
113 | return Optional.of(Short.parseShort(node.path(OVERRIDE_INTERVAL).asText())); | 113 | return Optional.of(Short.parseShort(node.path(OVERRIDE_INTERVAL).asText())); |
114 | } | 114 | } |
115 | + | ||
116 | + @Override | ||
117 | + public boolean isValid() { | ||
118 | + if (!hasOnlyFields(INTERFACE_NAME, ENABLED, HELLO_INTERVAL, HOLD_TIME, | ||
119 | + PRIORITY, PROPAGATION_DELAY, OVERRIDE_INTERVAL)) { | ||
120 | + return false; | ||
121 | + } | ||
122 | + | ||
123 | + return isString(INTERFACE_NAME, FieldPresence.MANDATORY) && | ||
124 | + isBoolean(ENABLED, FieldPresence.MANDATORY) && | ||
125 | + isIntegralNumber(HELLO_INTERVAL, FieldPresence.OPTIONAL) && | ||
126 | + isIntegralNumber(HOLD_TIME, FieldPresence.OPTIONAL) && | ||
127 | + isIntegralNumber(PRIORITY, FieldPresence.OPTIONAL) && | ||
128 | + isIntegralNumber(PROPAGATION_DELAY, FieldPresence.OPTIONAL) && | ||
129 | + isIntegralNumber(OVERRIDE_INTERVAL, FieldPresence.OPTIONAL); | ||
130 | + } | ||
115 | } | 131 | } | ... | ... |
... | @@ -82,4 +82,19 @@ public class RouterConfig extends Config<ApplicationId> { | ... | @@ -82,4 +82,19 @@ public class RouterConfig extends Config<ApplicationId> { |
82 | return interfaces; | 82 | return interfaces; |
83 | } | 83 | } |
84 | 84 | ||
85 | + @Override | ||
86 | + public boolean isValid() { | ||
87 | + if (!hasOnlyFields(INTERFACES, CP_CONNECT_POINT, OSPF_ENABLED, PIM_ENABLED)) { | ||
88 | + return false; | ||
89 | + } | ||
90 | + | ||
91 | + JsonNode intfNode = object.path(INTERFACES); | ||
92 | + if (!intfNode.isMissingNode() && !intfNode.isArray()) { | ||
93 | + return false; | ||
94 | + } | ||
95 | + | ||
96 | + return isConnectPoint(CP_CONNECT_POINT, FieldPresence.MANDATORY) && | ||
97 | + isBoolean(OSPF_ENABLED, FieldPresence.OPTIONAL) && | ||
98 | + isBoolean(PIM_ENABLED, FieldPresence.OPTIONAL); | ||
99 | + } | ||
85 | } | 100 | } | ... | ... |
... | @@ -24,7 +24,9 @@ import com.google.common.collect.ImmutableSet; | ... | @@ -24,7 +24,9 @@ import com.google.common.collect.ImmutableSet; |
24 | import com.google.common.collect.Iterators; | 24 | import com.google.common.collect.Iterators; |
25 | import com.google.common.collect.Lists; | 25 | import com.google.common.collect.Lists; |
26 | import org.onlab.packet.IpAddress; | 26 | import org.onlab.packet.IpAddress; |
27 | +import org.onlab.packet.IpPrefix; | ||
27 | import org.onlab.packet.MacAddress; | 28 | import org.onlab.packet.MacAddress; |
29 | +import org.onosproject.net.ConnectPoint; | ||
28 | 30 | ||
29 | import java.util.Collection; | 31 | import java.util.Collection; |
30 | import java.util.List; | 32 | import java.util.List; |
... | @@ -46,6 +48,9 @@ import static com.google.common.base.Preconditions.checkState; | ... | @@ -46,6 +48,9 @@ import static com.google.common.base.Preconditions.checkState; |
46 | @Beta | 48 | @Beta |
47 | public abstract class Config<S> { | 49 | public abstract class Config<S> { |
48 | 50 | ||
51 | + private static final String TRUE_LITERAL = "true"; | ||
52 | + private static final String FALSE_LITERAL = "false"; | ||
53 | + | ||
49 | protected S subject; | 54 | protected S subject; |
50 | protected String key; | 55 | protected String key; |
51 | 56 | ||
... | @@ -111,6 +116,8 @@ public abstract class Config<S> { | ... | @@ -111,6 +116,8 @@ public abstract class Config<S> { |
111 | // isDecimal(path, [min, max]) | 116 | // isDecimal(path, [min, max]) |
112 | // isMacAddress(path) | 117 | // isMacAddress(path) |
113 | // isIpAddress(path) | 118 | // isIpAddress(path) |
119 | + // isIpPrefix(path) | ||
120 | + // isConnectPoint(path) | ||
114 | return true; | 121 | return true; |
115 | } | 122 | } |
116 | 123 | ||
... | @@ -424,6 +431,22 @@ public abstract class Config<S> { | ... | @@ -424,6 +431,22 @@ public abstract class Config<S> { |
424 | } | 431 | } |
425 | 432 | ||
426 | /** | 433 | /** |
434 | + * Indicates whether the specified field of a particular node holds a valid | ||
435 | + * MAC address. | ||
436 | + * | ||
437 | + * @param objectNode JSON node | ||
438 | + * @param field JSON field name | ||
439 | + * @param presence specifies if field is optional or mandatory | ||
440 | + * @return true if valid; false otherwise | ||
441 | + * @throws IllegalArgumentException if field is present, but not valid MAC | ||
442 | + */ | ||
443 | + protected boolean isMacAddress(ObjectNode objectNode, String field, FieldPresence presence) { | ||
444 | + JsonNode node = objectNode.path(field); | ||
445 | + return isValid(node, presence, node.isTextual() && | ||
446 | + MacAddress.valueOf(node.asText()) != null); | ||
447 | + } | ||
448 | + | ||
449 | + /** | ||
427 | * Indicates whether the specified field holds a valid IP address. | 450 | * Indicates whether the specified field holds a valid IP address. |
428 | * | 451 | * |
429 | * @param field JSON field name | 452 | * @param field JSON field name |
... | @@ -439,16 +462,76 @@ public abstract class Config<S> { | ... | @@ -439,16 +462,76 @@ public abstract class Config<S> { |
439 | * Indicates whether the specified field of a particular node holds a valid | 462 | * Indicates whether the specified field of a particular node holds a valid |
440 | * IP address. | 463 | * IP address. |
441 | * | 464 | * |
442 | - * @param node node from whom to access the field | 465 | + * @param objectNode node from whom to access the field |
466 | + * @param field JSON field name | ||
467 | + * @param presence specifies if field is optional or mandatory | ||
468 | + * @return true if valid; false otherwise | ||
469 | + * @throws IllegalArgumentException if field is present, but not valid IP | ||
470 | + */ | ||
471 | + protected boolean isIpAddress(ObjectNode objectNode, String field, FieldPresence presence) { | ||
472 | + JsonNode node = objectNode.path(field); | ||
473 | + return isValid(node, presence, node.isTextual() && | ||
474 | + IpAddress.valueOf(node.asText()) != null); | ||
475 | + } | ||
476 | + | ||
477 | + /** | ||
478 | + * Indicates whether the specified field holds a valid IP prefix. | ||
479 | + * | ||
480 | + * @param field JSON field name | ||
481 | + * @param presence specifies if field is optional or mandatory | ||
482 | + * @return true if valid; false otherwise | ||
483 | + * @throws IllegalArgumentException if field is present, but not valid IP | ||
484 | + * prefix | ||
485 | + */ | ||
486 | + protected boolean isIpPrefix(String field, FieldPresence presence) { | ||
487 | + return isIpPrefix(object, field, presence); | ||
488 | + } | ||
489 | + | ||
490 | + /** | ||
491 | + * Indicates whether the specified field of a particular node holds a valid | ||
492 | + * IP prefix. | ||
493 | + * | ||
494 | + * @param objectNode node from whom to access the field | ||
443 | * @param field JSON field name | 495 | * @param field JSON field name |
444 | * @param presence specifies if field is optional or mandatory | 496 | * @param presence specifies if field is optional or mandatory |
445 | * @return true if valid; false otherwise | 497 | * @return true if valid; false otherwise |
446 | * @throws IllegalArgumentException if field is present, but not valid IP | 498 | * @throws IllegalArgumentException if field is present, but not valid IP |
499 | + * prefix | ||
500 | + */ | ||
501 | + protected boolean isIpPrefix(ObjectNode objectNode, String field, FieldPresence presence) { | ||
502 | + JsonNode node = objectNode.path(field); | ||
503 | + return isValid(node, presence, node.isTextual() && | ||
504 | + IpPrefix.valueOf(node.asText()) != null); | ||
505 | + } | ||
506 | + | ||
507 | + /** | ||
508 | + * Indicates whether the specified field holds a valid connect point string. | ||
509 | + * | ||
510 | + * @param field JSON field name | ||
511 | + * @param presence specifies if field is optional or mandatory | ||
512 | + * @return true if valid; false otherwise | ||
513 | + * @throws IllegalArgumentException if field is present, but not valid | ||
514 | + * connect point string representation | ||
515 | + */ | ||
516 | + protected boolean isConnectPoint(String field, FieldPresence presence) { | ||
517 | + return isConnectPoint(object, field, presence); | ||
518 | + } | ||
519 | + | ||
520 | + /** | ||
521 | + * Indicates whether the specified field of a particular node holds a valid | ||
522 | + * connect point string. | ||
523 | + * | ||
524 | + * @param objectNode JSON node | ||
525 | + * @param field JSON field name | ||
526 | + * @param presence specifies if field is optional or mandatory | ||
527 | + * @return true if valid; false otherwise | ||
528 | + * @throws IllegalArgumentException if field is present, but not valid | ||
529 | + * connect point string representation | ||
447 | */ | 530 | */ |
448 | - protected boolean isIpAddress(ObjectNode node, String field, FieldPresence presence) { | 531 | + protected boolean isConnectPoint(ObjectNode objectNode, String field, FieldPresence presence) { |
449 | - JsonNode innerNode = node.path(field); | 532 | + JsonNode node = objectNode.path(field); |
450 | - return isValid(innerNode, presence, innerNode.isTextual() && | 533 | + return isValid(node, presence, node.isTextual() && |
451 | - IpAddress.valueOf(innerNode.asText()) != null); | 534 | + ConnectPoint.deviceConnectPoint(node.asText()) != null); |
452 | } | 535 | } |
453 | 536 | ||
454 | /** | 537 | /** |
... | @@ -458,10 +541,26 @@ public abstract class Config<S> { | ... | @@ -458,10 +541,26 @@ public abstract class Config<S> { |
458 | * @param presence specifies if field is optional or mandatory | 541 | * @param presence specifies if field is optional or mandatory |
459 | * @param pattern optional regex pattern | 542 | * @param pattern optional regex pattern |
460 | * @return true if valid; false otherwise | 543 | * @return true if valid; false otherwise |
461 | - * @throws IllegalArgumentException if field is present, but not valid MAC | 544 | + * @throws IllegalArgumentException if field is present, but not valid string |
462 | */ | 545 | */ |
463 | protected boolean isString(String field, FieldPresence presence, String... pattern) { | 546 | protected boolean isString(String field, FieldPresence presence, String... pattern) { |
464 | - JsonNode node = object.path(field); | 547 | + return isString(object, field, presence, pattern); |
548 | + } | ||
549 | + | ||
550 | + /** | ||
551 | + * Indicates whether the specified field on a particular node holds a valid | ||
552 | + * string value. | ||
553 | + * | ||
554 | + * @param objectNode JSON node | ||
555 | + * @param field JSON field name | ||
556 | + * @param presence specifies if field is optional or mandatory | ||
557 | + * @param pattern optional regex pattern | ||
558 | + * @return true if valid; false otherwise | ||
559 | + * @throws IllegalArgumentException if field is present, but not valid string | ||
560 | + */ | ||
561 | + protected boolean isString(ObjectNode objectNode, String field, | ||
562 | + FieldPresence presence, String... pattern) { | ||
563 | + JsonNode node = objectNode.path(field); | ||
465 | return isValid(node, presence, node.isTextual() && | 564 | return isValid(node, presence, node.isTextual() && |
466 | (pattern.length > 0 && node.asText().matches(pattern[0]) || pattern.length < 1)); | 565 | (pattern.length > 0 && node.asText().matches(pattern[0]) || pattern.length < 1)); |
467 | } | 566 | } |
... | @@ -507,10 +606,29 @@ public abstract class Config<S> { | ... | @@ -507,10 +606,29 @@ public abstract class Config<S> { |
507 | * @throws IllegalArgumentException if field is present, but not valid | 606 | * @throws IllegalArgumentException if field is present, but not valid |
508 | */ | 607 | */ |
509 | protected boolean isIntegralNumber(String field, FieldPresence presence, long... minMax) { | 608 | protected boolean isIntegralNumber(String field, FieldPresence presence, long... minMax) { |
510 | - JsonNode node = object.path(field); | 609 | + return isIntegralNumber(object, field, presence, minMax); |
511 | - return isValid(node, presence, node.isIntegralNumber() && | 610 | + } |
512 | - (minMax.length > 0 && minMax[0] <= node.asLong() || minMax.length < 1) && | 611 | + |
513 | - (minMax.length > 1 && minMax[1] > node.asLong() || minMax.length < 2)); | 612 | + /** |
613 | + * Indicates whether the specified field of a particular node holds a valid | ||
614 | + * integer. | ||
615 | + * | ||
616 | + * @param objectNode JSON node | ||
617 | + * @param field JSON field name | ||
618 | + * @param presence specifies if field is optional or mandatory | ||
619 | + * @param minMax optional min/max values | ||
620 | + * @return true if valid; false otherwise | ||
621 | + * @throws IllegalArgumentException if field is present, but not valid | ||
622 | + */ | ||
623 | + protected boolean isIntegralNumber(ObjectNode objectNode, String field, | ||
624 | + FieldPresence presence, long... minMax) { | ||
625 | + JsonNode node = objectNode.path(field); | ||
626 | + | ||
627 | + return isValid(node, presence, n -> { | ||
628 | + long number = (node.isIntegralNumber()) ? n.asLong() : Long.parseLong(n.asText()); | ||
629 | + return (minMax.length > 0 && minMax[0] <= number || minMax.length < 1) && | ||
630 | + (minMax.length > 1 && minMax[1] > number || minMax.length < 2); | ||
631 | + }); | ||
514 | } | 632 | } |
515 | 633 | ||
516 | /** | 634 | /** |
... | @@ -535,11 +653,35 @@ public abstract class Config<S> { | ... | @@ -535,11 +653,35 @@ public abstract class Config<S> { |
535 | * @param field JSON field name | 653 | * @param field JSON field name |
536 | * @param presence specifies if field is optional or mandatory | 654 | * @param presence specifies if field is optional or mandatory |
537 | * @return true if valid; false otherwise | 655 | * @return true if valid; false otherwise |
538 | - * @throws IllegalArgumentException if field is present, but not valid | ||
539 | */ | 656 | */ |
540 | protected boolean isBoolean(String field, FieldPresence presence) { | 657 | protected boolean isBoolean(String field, FieldPresence presence) { |
541 | - JsonNode node = object.path(field); | 658 | + return isBoolean(object, field, presence); |
542 | - return isValid(node, presence, node.isBoolean()); | 659 | + } |
660 | + | ||
661 | + /** | ||
662 | + * Indicates whether the specified field of a particular node holds a valid | ||
663 | + * boolean value. | ||
664 | + * | ||
665 | + * @param objectNode JSON object node | ||
666 | + * @param field JSON field name | ||
667 | + * @param presence specifies if field is optional or mandatory | ||
668 | + * @return true if valid; false otherwise | ||
669 | + */ | ||
670 | + protected boolean isBoolean(ObjectNode objectNode, String field, FieldPresence presence) { | ||
671 | + JsonNode node = objectNode.path(field); | ||
672 | + return isValid(node, presence, node.isBoolean() || | ||
673 | + (node.isTextual() && isBooleanString(node.asText()))); | ||
674 | + } | ||
675 | + | ||
676 | + /** | ||
677 | + * Indicates whether a string holds a boolean literal value. | ||
678 | + * | ||
679 | + * @param str string to test | ||
680 | + * @return true if the string contains "true" or "false" (case insensitive), | ||
681 | + * otherwise false | ||
682 | + */ | ||
683 | + private boolean isBooleanString(String str) { | ||
684 | + return str.equalsIgnoreCase(TRUE_LITERAL) || str.equalsIgnoreCase(FALSE_LITERAL); | ||
543 | } | 685 | } |
544 | 686 | ||
545 | /** | 687 | /** |
... | @@ -552,7 +694,30 @@ public abstract class Config<S> { | ... | @@ -552,7 +694,30 @@ public abstract class Config<S> { |
552 | * @return true if the field is as expected | 694 | * @return true if the field is as expected |
553 | */ | 695 | */ |
554 | private boolean isValid(JsonNode node, FieldPresence presence, boolean correctValue) { | 696 | private boolean isValid(JsonNode node, FieldPresence presence, boolean correctValue) { |
697 | + return isValid(node, presence, n -> correctValue); | ||
698 | + } | ||
699 | + | ||
700 | + /** | ||
701 | + * Indicates whether the node is present and of correct value or not | ||
702 | + * mandatory and absent. | ||
703 | + * | ||
704 | + * @param node JSON node | ||
705 | + * @param presence specified if field is optional or mandatory | ||
706 | + * @param validationFunction function which can be used to verify if the | ||
707 | + * node has the correct value | ||
708 | + * @return true if the field is as expected | ||
709 | + */ | ||
710 | + private boolean isValid(JsonNode node, FieldPresence presence, | ||
711 | + Function<JsonNode, Boolean> validationFunction) { | ||
555 | boolean isMandatory = presence == FieldPresence.MANDATORY; | 712 | boolean isMandatory = presence == FieldPresence.MANDATORY; |
556 | - return isMandatory && correctValue || !isMandatory && !node.isNull() || correctValue; | 713 | + if (isMandatory && validationFunction.apply(node)) { |
714 | + return true; | ||
715 | + } | ||
716 | + | ||
717 | + if (!isMandatory && (node.isNull() || node.isMissingNode())) { | ||
718 | + return true; | ||
719 | + } | ||
720 | + | ||
721 | + return validationFunction.apply(node); | ||
557 | } | 722 | } |
558 | } | 723 | } | ... | ... |
... | @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; | ... | @@ -22,6 +22,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; |
22 | import com.google.common.annotations.Beta; | 22 | import com.google.common.annotations.Beta; |
23 | import com.google.common.collect.Lists; | 23 | import com.google.common.collect.Lists; |
24 | import com.google.common.collect.Sets; | 24 | import com.google.common.collect.Sets; |
25 | +import org.onlab.packet.IpPrefix; | ||
25 | import org.onlab.packet.MacAddress; | 26 | import org.onlab.packet.MacAddress; |
26 | import org.onlab.packet.VlanId; | 27 | import org.onlab.packet.VlanId; |
27 | import org.onosproject.incubator.net.intf.Interface; | 28 | import org.onosproject.incubator.net.intf.Interface; |
... | @@ -50,6 +51,31 @@ public class InterfaceConfig extends Config<ConnectPoint> { | ... | @@ -50,6 +51,31 @@ public class InterfaceConfig extends Config<ConnectPoint> { |
50 | private static final String INTF_NULL_ERROR = "Interface cannot be null"; | 51 | private static final String INTF_NULL_ERROR = "Interface cannot be null"; |
51 | private static final String INTF_NAME_ERROR = "Interface must have a valid name"; | 52 | private static final String INTF_NAME_ERROR = "Interface must have a valid name"; |
52 | 53 | ||
54 | + @Override | ||
55 | + public boolean isValid() { | ||
56 | + for (JsonNode node : array) { | ||
57 | + if (!hasOnlyFields((ObjectNode) node, NAME, IPS, MAC, VLAN)) { | ||
58 | + return false; | ||
59 | + } | ||
60 | + | ||
61 | + ObjectNode obj = (ObjectNode) node; | ||
62 | + | ||
63 | + if (!(isString(obj, NAME, FieldPresence.OPTIONAL) && | ||
64 | + isMacAddress(obj, MAC, FieldPresence.OPTIONAL) && | ||
65 | + isIntegralNumber(obj, VLAN, FieldPresence.OPTIONAL, 0, VlanId.MAX_VLAN))) { | ||
66 | + return false; | ||
67 | + } | ||
68 | + | ||
69 | + | ||
70 | + for (JsonNode ipNode : node.path(IPS)) { | ||
71 | + if (!ipNode.isTextual() || IpPrefix.valueOf(ipNode.asText()) == null) { | ||
72 | + return false; | ||
73 | + } | ||
74 | + } | ||
75 | + } | ||
76 | + return true; | ||
77 | + } | ||
78 | + | ||
53 | /** | 79 | /** |
54 | * Retrieves all interfaces configured on this port. | 80 | * Retrieves all interfaces configured on this port. |
55 | * | 81 | * | ... | ... |
-
Please register or login to post a comment