1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package flowcontrol 18 19 import ( 20 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 21 ) 22 23 // These are valid wildcards. 24 const ( 25 APIGroupAll = "*" 26 ResourceAll = "*" 27 VerbAll = "*" 28 NonResourceAll = "*" 29 NameAll = "*" 30 31 NamespaceEvery = "*" // matches every particular namespace 32 ) 33 34 // System preset priority level names 35 const ( 36 PriorityLevelConfigurationNameExempt = "exempt" 37 PriorityLevelConfigurationNameCatchAll = "catch-all" 38 FlowSchemaNameExempt = "exempt" 39 FlowSchemaNameCatchAll = "catch-all" 40 ) 41 42 // Conditions 43 const ( 44 FlowSchemaConditionDangling = "Dangling" 45 46 PriorityLevelConfigurationConditionConcurrencyShared = "ConcurrencyShared" 47 ) 48 49 // Constants used by api validation. 50 const ( 51 FlowSchemaMaxMatchingPrecedence int32 = 10000 52 ) 53 54 // +genclient 55 // +genclient:nonNamespaced 56 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 57 58 // FlowSchema defines the schema of a group of flows. Note that a flow is made up of a set of inbound API requests with 59 // similar attributes and is identified by a pair of strings: the name of the FlowSchema and a "flow distinguisher". 60 type FlowSchema struct { 61 metav1.TypeMeta 62 // `metadata` is the standard object's metadata. 63 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 64 // +optional 65 metav1.ObjectMeta 66 // `spec` is the specification of the desired behavior of a FlowSchema. 67 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status 68 // +optional 69 Spec FlowSchemaSpec 70 // `status` is the current status of a FlowSchema. 71 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status 72 // +optional 73 Status FlowSchemaStatus 74 } 75 76 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 77 78 // FlowSchemaList is a list of FlowSchema objects. 79 type FlowSchemaList struct { 80 metav1.TypeMeta 81 // `metadata` is the standard list metadata. 82 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 83 // +optional 84 metav1.ListMeta 85 86 // `items` is a list of FlowSchemas. 87 Items []FlowSchema 88 } 89 90 // FlowSchemaSpec describes how the FlowSchema's specification looks like. 91 type FlowSchemaSpec struct { 92 // `priorityLevelConfiguration` should reference a PriorityLevelConfiguration in the cluster. If the reference cannot 93 // be resolved, the FlowSchema will be ignored and marked as invalid in its status. 94 // Required. 95 PriorityLevelConfiguration PriorityLevelConfigurationReference 96 // `matchingPrecedence` is used to choose among the FlowSchemas that match a given request. The chosen 97 // FlowSchema is among those with the numerically lowest (which we take to be logically highest) 98 // MatchingPrecedence. Each MatchingPrecedence value must be ranged in [1,10000]. 99 // Note that if the precedence is not specified, it will be set to 1000 as default. 100 // +optional 101 MatchingPrecedence int32 102 // `distinguisherMethod` defines how to compute the flow distinguisher for requests that match this schema. 103 // `nil` specifies that the distinguisher is disabled and thus will always be the empty string. 104 // +optional 105 DistinguisherMethod *FlowDistinguisherMethod 106 // `rules` describes which requests will match this flow schema. This FlowSchema matches a request if and only if 107 // at least one member of rules matches the request. 108 // if it is an empty slice, there will be no requests matching the FlowSchema. 109 // +listType=set 110 // +optional 111 Rules []PolicyRulesWithSubjects 112 } 113 114 // FlowDistinguisherMethodType is the type of flow distinguisher method 115 type FlowDistinguisherMethodType string 116 117 // These are valid flow-distinguisher methods. 118 const ( 119 // FlowDistinguisherMethodByUserType specifies that the flow distinguisher is the username in the request. 120 // This type is used to provide some insulation between users. 121 FlowDistinguisherMethodByUserType FlowDistinguisherMethodType = "ByUser" 122 123 // FlowDistinguisherMethodByNamespaceType specifies that the flow distinguisher is the namespace of the 124 // object that the request acts upon. If the object is not namespaced, or if the request is a non-resource 125 // request, then the distinguisher will be the empty string. An example usage of this type is to provide 126 // some insulation between tenants in a situation where there are multiple tenants and each namespace 127 // is dedicated to a tenant. 128 FlowDistinguisherMethodByNamespaceType FlowDistinguisherMethodType = "ByNamespace" 129 ) 130 131 // FlowDistinguisherMethod specifies the method of a flow distinguisher. 132 type FlowDistinguisherMethod struct { 133 // `type` is the type of flow distinguisher method 134 // The supported types are "ByUser" and "ByNamespace". 135 // Required. 136 Type FlowDistinguisherMethodType 137 } 138 139 // PriorityLevelConfigurationReference contains information that points to the "request-priority" being used. 140 type PriorityLevelConfigurationReference struct { 141 // `name` is the name of the priority level configuration being referenced 142 // Required. 143 Name string 144 } 145 146 // PolicyRulesWithSubjects prescribes a test that applies to a request to an apiserver. The test considers the subject 147 // making the request, the verb being requested, and the resource to be acted upon. This PolicyRulesWithSubjects matches 148 // a request if and only if both (a) at least one member of subjects matches the request and (b) at least one member 149 // of resourceRules or nonResourceRules matches the request. 150 type PolicyRulesWithSubjects struct { 151 // subjects is the list of normal user, serviceaccount, or group that this rule cares about. 152 // There must be at least one member in this slice. 153 // A slice that includes both the system:authenticated and system:unauthenticated user groups matches every request. 154 // +listType=set 155 // Required. 156 Subjects []Subject 157 // `resourceRules` is a slice of ResourcePolicyRules that identify matching requests according to their verb and the 158 // target resource. 159 // At least one of `resourceRules` and `nonResourceRules` has to be non-empty. 160 // +listType=set 161 // +optional 162 ResourceRules []ResourcePolicyRule 163 // `nonResourceRules` is a list of NonResourcePolicyRules that identify matching requests according to their verb 164 // and the target non-resource URL. 165 // +listType=set 166 // +optional 167 NonResourceRules []NonResourcePolicyRule 168 } 169 170 // Subject matches the originator of a request, as identified by the request authentication system. There are three 171 // ways of matching an originator; by user, group, or service account. 172 // +union 173 type Subject struct { 174 // `kind` indicates which one of the other fields is non-empty. 175 // Required 176 // +unionDiscriminator 177 Kind SubjectKind 178 // `user` matches based on username. 179 // +optional 180 User *UserSubject 181 // `group` matches based on user group name. 182 // +optional 183 Group *GroupSubject 184 // `serviceAccount` matches ServiceAccounts. 185 // +optional 186 ServiceAccount *ServiceAccountSubject 187 } 188 189 // SubjectKind is the kind of subject. 190 type SubjectKind string 191 192 // Supported subject's kinds. 193 const ( 194 SubjectKindUser SubjectKind = "User" 195 SubjectKindGroup SubjectKind = "Group" 196 SubjectKindServiceAccount SubjectKind = "ServiceAccount" 197 ) 198 199 // UserSubject holds detailed information for user-kind subject. 200 type UserSubject struct { 201 // `name` is the username that matches, or "*" to match all usernames. 202 // Required. 203 Name string 204 } 205 206 // GroupSubject holds detailed information for group-kind subject. 207 type GroupSubject struct { 208 // name is the user group that matches, or "*" to match all user groups. 209 // See https://github.com/kubernetes/apiserver/blob/master/pkg/authentication/user/user.go for some 210 // well-known group names. 211 // Required. 212 Name string 213 } 214 215 // ServiceAccountSubject holds detailed information for service-account-kind subject. 216 type ServiceAccountSubject struct { 217 // `namespace` is the namespace of matching ServiceAccount objects. 218 // Required. 219 Namespace string 220 // `name` is the name of matching ServiceAccount objects, or "*" to match regardless of name. 221 // Required. 222 Name string 223 } 224 225 // ResourcePolicyRule is a predicate that matches some resource 226 // requests, testing the request's verb and the target resource. A 227 // ResourcePolicyRule matches a resource request if and only if: (a) 228 // at least one member of verbs matches the request, (b) at least one 229 // member of apiGroups matches the request, (c) at least one member of 230 // resources matches the request, and (d) least one member of 231 // namespaces matches the request. 232 type ResourcePolicyRule struct { 233 // `verbs` is a list of matching verbs and may not be empty. 234 // "*" matches all verbs and, if present, must be the only entry. 235 // +listType=set 236 // Required. 237 Verbs []string 238 239 // `apiGroups` is a list of matching API groups and may not be empty. 240 // "*" matches all API groups and, if present, must be the only entry. 241 // +listType=set 242 // Required. 243 APIGroups []string 244 245 // `resources` is a list of matching resources (i.e., lowercase 246 // and plural) with, if desired, subresource. For example, [ 247 // "services", "nodes/status" ]. This list may not be empty. 248 // "*" matches all resources and, if present, must be the only entry. 249 // Required. 250 // +listType=set 251 Resources []string 252 253 // `clusterScope` indicates whether to match requests that do not 254 // specify a namespace (which happens either because the resource 255 // is not namespaced or the request targets all namespaces). 256 // If this field is omitted or false then the `namespaces` field 257 // must contain a non-empty list. 258 // +optional 259 ClusterScope bool 260 261 // `namespaces` is a list of target namespaces that restricts 262 // matches. A request that specifies a target namespace matches 263 // only if either (a) this list contains that target namespace or 264 // (b) this list contains "*". Note that "*" matches any 265 // specified namespace but does not match a request that _does 266 // not specify_ a namespace (see the `clusterScope` field for 267 // that). 268 // This list may be empty, but only if `clusterScope` is true. 269 // +optional 270 // +listType=set 271 Namespaces []string 272 } 273 274 // NonResourcePolicyRule is a predicate that matches non-resource requests according to their verb and the 275 // target non-resource URL. A NonResourcePolicyRule matches a request if and only if both (a) at least one member 276 // of verbs matches the request and (b) at least one member of nonResourceURLs matches the request. 277 type NonResourcePolicyRule struct { 278 // `verbs` is a list of matching verbs and may not be empty. 279 // "*" matches all verbs. If it is present, it must be the only entry. 280 // +listType=set 281 // Required. 282 Verbs []string 283 // `nonResourceURLs` is a set of url prefixes that a user should have access to and may not be empty. 284 // For example: 285 // - "/healthz" is legal 286 // - "/hea*" is illegal 287 // - "/hea" is legal but matches nothing 288 // - "/hea/*" also matches nothing 289 // - "/healthz/*" matches all per-component health checks. 290 // "*" matches all non-resource urls. if it is present, it must be the only entry. 291 // +listType=set 292 // Required. 293 NonResourceURLs []string 294 } 295 296 // FlowSchemaStatus represents the current state of a FlowSchema. 297 type FlowSchemaStatus struct { 298 // `conditions` is a list of the current states of FlowSchema. 299 // +listType=map 300 // +listMapKey=type 301 // +patchMergeKey=type 302 // +patchStrategy=merge 303 // +optional 304 Conditions []FlowSchemaCondition 305 } 306 307 // FlowSchemaCondition describes conditions for a FlowSchema. 308 type FlowSchemaCondition struct { 309 // `type` is the type of the condition. 310 // Required. 311 Type FlowSchemaConditionType 312 // `status` is the status of the condition. 313 // Can be True, False, Unknown. 314 // Required. 315 Status ConditionStatus 316 // `lastTransitionTime` is the last time the condition transitioned from one status to another. 317 LastTransitionTime metav1.Time 318 // `reason` is a unique, one-word, CamelCase reason for the condition's last transition. 319 Reason string 320 // `message` is a human-readable message indicating details about last transition. 321 Message string 322 } 323 324 // FlowSchemaConditionType is a valid value for FlowSchemaStatusCondition.Type 325 type FlowSchemaConditionType string 326 327 // +genclient 328 // +genclient:nonNamespaced 329 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 330 331 // PriorityLevelConfiguration represents the configuration of a priority level. 332 type PriorityLevelConfiguration struct { 333 metav1.TypeMeta 334 // `metadata` is the standard object's metadata. 335 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 336 // +optional 337 metav1.ObjectMeta 338 // `spec` is the specification of the desired behavior of a "request-priority". 339 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status 340 // +optional 341 Spec PriorityLevelConfigurationSpec 342 // `status` is the current status of a "request-priority". 343 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status 344 // +optional 345 Status PriorityLevelConfigurationStatus 346 } 347 348 // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object 349 350 // PriorityLevelConfigurationList is a list of PriorityLevelConfiguration objects. 351 type PriorityLevelConfigurationList struct { 352 metav1.TypeMeta 353 // `metadata` is the standard object's metadata. 354 // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata 355 // +optional 356 metav1.ListMeta 357 // `items` is a list of request-priorities. 358 Items []PriorityLevelConfiguration 359 } 360 361 // PriorityLevelConfigurationSpec specifies the configuration of a priority level. 362 // +union 363 type PriorityLevelConfigurationSpec struct { 364 // `type` indicates whether this priority level is subject to 365 // limitation on request execution. A value of `"Exempt"` means 366 // that requests of this priority level are not subject to a limit 367 // (and thus are never queued) and do not detract from the 368 // capacity made available to other priority levels. A value of 369 // `"Limited"` means that (a) requests of this priority level 370 // _are_ subject to limits and (b) some of the server's limited 371 // capacity is made available exclusively to this priority level. 372 // Required. 373 // +unionDiscriminator 374 Type PriorityLevelEnablement 375 376 // `limited` specifies how requests are handled for a Limited priority level. 377 // This field must be non-empty if and only if `type` is `"Limited"`. 378 // +optional 379 Limited *LimitedPriorityLevelConfiguration 380 381 // `exempt` specifies how requests are handled for an exempt priority level. 382 // This field MUST be empty if `type` is `"Limited"`. 383 // This field MAY be non-empty if `type` is `"Exempt"`. 384 // If empty and `type` is `"Exempt"` then the default values 385 // for `ExemptPriorityLevelConfiguration` apply. 386 // +optional 387 Exempt *ExemptPriorityLevelConfiguration 388 } 389 390 // PriorityLevelEnablement indicates whether limits on execution are enabled for the priority level 391 type PriorityLevelEnablement string 392 393 // Supported priority level enablement values. 394 const ( 395 // PriorityLevelEnablementExempt means that requests are not subject to limits 396 PriorityLevelEnablementExempt PriorityLevelEnablement = "Exempt" 397 398 // PriorityLevelEnablementLimited means that requests are subject to limits 399 PriorityLevelEnablementLimited PriorityLevelEnablement = "Limited" 400 ) 401 402 // LimitedPriorityLevelConfiguration specifies how to handle requests that are subject to limits. 403 // It addresses two issues: 404 // - How are requests for this priority level limited? 405 // - What should be done with requests that exceed the limit? 406 type LimitedPriorityLevelConfiguration struct { 407 // `nominalConcurrencyShares` (NCS) contributes to the computation of the 408 // NominalConcurrencyLimit (NominalCL) of this level. 409 // This is the number of execution seats available at this priority level. 410 // This is used both for requests dispatched from this priority level 411 // as well as requests dispatched from other priority levels 412 // borrowing seats from this level. 413 // The server's concurrency limit (ServerCL) is divided among the 414 // Limited priority levels in proportion to their NCS values: 415 // 416 // NominalCL(i) = ceil( ServerCL * NCS(i) / sum_ncs ) 417 // sum_ncs = sum[priority level k] NCS(k) 418 // 419 // Bigger numbers mean a larger nominal concurrency limit, 420 // at the expense of every other priority level. 421 // This field has a default value of 30. 422 // 423 // Setting this field to zero supports the construction of a 424 // "jail" for this priority level that is used to hold some request(s) 425 // 426 // +optional 427 NominalConcurrencyShares int32 428 429 // `limitResponse` indicates what to do with requests that can not be executed right now 430 LimitResponse LimitResponse 431 432 // `lendablePercent` prescribes the fraction of the level's NominalCL that 433 // can be borrowed by other priority levels. The value of this 434 // field must be between 0 and 100, inclusive, and it defaults to 0. 435 // The number of seats that other levels can borrow from this level, known 436 // as this level's LendableConcurrencyLimit (LendableCL), is defined as follows. 437 // 438 // LendableCL(i) = round( NominalCL(i) * lendablePercent(i)/100.0 ) 439 // 440 // +optional 441 LendablePercent *int32 442 443 // `borrowingLimitPercent`, if present, configures a limit on how many 444 // seats this priority level can borrow from other priority levels. 445 // The limit is known as this level's BorrowingConcurrencyLimit 446 // (BorrowingCL) and is a limit on the total number of seats that this 447 // level may borrow at any one time. 448 // This field holds the ratio of that limit to the level's nominal 449 // concurrency limit. When this field is non-nil, it must hold a 450 // non-negative integer and the limit is calculated as follows. 451 // 452 // BorrowingCL(i) = round( NominalCL(i) * borrowingLimitPercent(i)/100.0 ) 453 // 454 // The value of this field can be more than 100, implying that this 455 // priority level can borrow a number of seats that is greater than 456 // its own nominal concurrency limit (NominalCL). 457 // When this field is left `nil`, the limit is effectively infinite. 458 // +optional 459 BorrowingLimitPercent *int32 460 } 461 462 // ExemptPriorityLevelConfiguration describes the configurable aspects 463 // of the handling of exempt requests. 464 // In the mandatory exempt configuration object the values in the fields 465 // here can be modified by authorized users, unlike the rest of the `spec`. 466 type ExemptPriorityLevelConfiguration struct { 467 // `nominalConcurrencyShares` (NCS) contributes to the computation of the 468 // NominalConcurrencyLimit (NominalCL) of this level. 469 // This is the number of execution seats nominally reserved for this priority level. 470 // This DOES NOT limit the dispatching from this priority level 471 // but affects the other priority levels through the borrowing mechanism. 472 // The server's concurrency limit (ServerCL) is divided among all the 473 // priority levels in proportion to their NCS values: 474 // 475 // NominalCL(i) = ceil( ServerCL * NCS(i) / sum_ncs ) 476 // sum_ncs = sum[priority level k] NCS(k) 477 // 478 // Bigger numbers mean a larger nominal concurrency limit, 479 // at the expense of every other priority level. 480 // This field has a default value of zero. 481 // +optional 482 NominalConcurrencyShares *int32 483 // `lendablePercent` prescribes the fraction of the level's NominalCL that 484 // can be borrowed by other priority levels. This value of this 485 // field must be between 0 and 100, inclusive, and it defaults to 0. 486 // The number of seats that other levels can borrow from this level, known 487 // as this level's LendableConcurrencyLimit (LendableCL), is defined as follows. 488 // 489 // LendableCL(i) = round( NominalCL(i) * lendablePercent(i)/100.0 ) 490 // 491 // +optional 492 LendablePercent *int32 493 // The `BorrowingCL` of an Exempt priority level is implicitly `ServerCL`. 494 // In other words, an exempt priority level 495 // has no meaningful limit on how much it borrows. 496 // There is no explicit representation of that here. 497 } 498 499 // LimitResponse defines how to handle requests that can not be executed right now. 500 // +union 501 type LimitResponse struct { 502 // `type` is "Queue" or "Reject". 503 // "Queue" means that requests that can not be executed upon arrival 504 // are held in a queue until they can be executed or a queuing limit 505 // is reached. 506 // "Reject" means that requests that can not be executed upon arrival 507 // are rejected. 508 // Required. 509 // +unionDiscriminator 510 Type LimitResponseType 511 512 // `queuing` holds the configuration parameters for queuing. 513 // This field may be non-empty only if `type` is `"Queue"`. 514 // +optional 515 Queuing *QueuingConfiguration 516 } 517 518 // LimitResponseType identifies how a Limited priority level handles a request that can not be executed right now 519 type LimitResponseType string 520 521 // Supported limit responses. 522 const ( 523 // LimitResponseTypeQueue means that requests that can not be executed right now are queued until they can be executed or a queuing limit is hit 524 LimitResponseTypeQueue LimitResponseType = "Queue" 525 526 // LimitResponseTypeReject means that requests that can not be executed right now are rejected 527 LimitResponseTypeReject LimitResponseType = "Reject" 528 ) 529 530 // QueuingConfiguration holds the configuration parameters for queuing 531 type QueuingConfiguration struct { 532 // `queues` is the number of queues for this priority level. The 533 // queues exist independently at each apiserver. The value must be 534 // positive. Setting it to 1 effectively precludes 535 // shufflesharding and thus makes the distinguisher method of 536 // associated flow schemas irrelevant. This field has a default 537 // value of 64. 538 // +optional 539 Queues int32 540 541 // `handSize` is a small positive number that configures the 542 // shuffle sharding of requests into queues. When enqueuing a request 543 // at this priority level the request's flow identifier (a string 544 // pair) is hashed and the hash value is used to shuffle the list 545 // of queues and deal a hand of the size specified here. The 546 // request is put into one of the shortest queues in that hand. 547 // `handSize` must be no larger than `queues`, and should be 548 // significantly smaller (so that a few heavy flows do not 549 // saturate most of the queues). See the user-facing 550 // documentation for more extensive guidance on setting this 551 // field. This field has a default value of 8. 552 // +optional 553 HandSize int32 554 555 // `queueLengthLimit` is the maximum number of requests allowed to 556 // be waiting in a given queue of this priority level at a time; 557 // excess requests are rejected. This value must be positive. If 558 // not specified, it will be defaulted to 50. 559 // +optional 560 QueueLengthLimit int32 561 } 562 563 // PriorityLevelConfigurationConditionType is a valid value for PriorityLevelConfigurationStatusCondition.Type 564 type PriorityLevelConfigurationConditionType string 565 566 // PriorityLevelConfigurationStatus represents the current state of a "request-priority". 567 type PriorityLevelConfigurationStatus struct { 568 // `conditions` is the current state of "request-priority". 569 // +listType=map 570 // +listMapKey=type 571 // +patchMergeKey=type 572 // +patchStrategy=merge 573 // +optional 574 Conditions []PriorityLevelConfigurationCondition 575 } 576 577 // PriorityLevelConfigurationCondition defines the condition of priority level. 578 type PriorityLevelConfigurationCondition struct { 579 // `type` is the type of the condition. 580 // Required. 581 Type PriorityLevelConfigurationConditionType 582 // `status` is the status of the condition. 583 // Can be True, False, Unknown. 584 // Required. 585 Status ConditionStatus 586 // `lastTransitionTime` is the last time the condition transitioned from one status to another. 587 LastTransitionTime metav1.Time 588 // `reason` is a unique, one-word, CamelCase reason for the condition's last transition. 589 Reason string 590 // `message` is a human-readable message indicating details about last transition. 591 Message string 592 } 593 594 // ConditionStatus is the status of the condition. 595 type ConditionStatus string 596 597 // These are valid condition statuses. "ConditionTrue" means a resource is in the condition. 598 // "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes 599 // can't decide if a resource is in the condition or not. In the future, we could add other 600 // intermediate conditions, e.g. ConditionDegraded. 601 const ( 602 ConditionTrue ConditionStatus = "True" 603 ConditionFalse ConditionStatus = "False" 604 ConditionUnknown ConditionStatus = "Unknown" 605 ) 606