sigs.k8s.io/cluster-api@v1.7.1/docs/proposals/20200506-conditions.md (about)

     1  ---
     2  title: Conditions
     3  authors:
     4    - "@fabriziopandini"
     5  reviewers:
     6    - "@vincepri"
     7    - "@ncdc"
     8  creation-date: 2020-05-06
     9  last-updated: 2020-05-20
    10  status: implementable
    11  see-also:
    12  replaces:
    13  superseded-by:
    14  ---
    15  
    16  # Conditions - Cluster status at glance
    17  
    18  ## Table of Contents
    19  
    20  <!-- START doctoc generated TOC please keep comment here to allow auto update -->
    21  <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
    22  
    23  - [Glossary](#glossary)
    24  - [Summary](#summary)
    25  - [Motivation](#motivation)
    26    - [Goals](#goals)
    27    - [Non-Goals/Future Work](#non-goalsfuture-work)
    28  - [Proposal](#proposal)
    29    - [User Stories](#user-stories)
    30      - [Story 1](#story-1)
    31      - [Story 2](#story-2)
    32      - [Story 3](#story-3)
    33      - [Story 4](#story-4)
    34    - [Implementation Details/Notes/Constraints](#implementation-detailsnotesconstraints)
    35      - [Data Model Changes](#data-model-changes)
    36      - [Constraints](#constraints)
    37        - [Condition semantic](#condition-semantic)
    38        - [The Ready condition](#the-ready-condition)
    39        - [Controller changes](#controller-changes)
    40      - [The cluster provisioning workflow](#the-cluster-provisioning-workflow)
    41        - [The `ClusterInfrastructureReady` condition](#the-clusterinfrastructureready-condition)
    42        - [The cluster’s `ControlPlaneReady` condition](#the-clusters-controlplaneready-condition)
    43        - [The cluster’s `WorkersReady` condition](#the-clusters-workersready-condition)
    44    - [The control plane upgrade workflow](#the-control-plane-upgrade-workflow)
    45    - [Risks and Mitigations](#risks-and-mitigations)
    46  - [Alternatives](#alternatives)
    47    - [Kubernetes Conditions](#kubernetes-conditions)
    48    - [Status field](#status-field)
    49  - [Upgrade Strategy](#upgrade-strategy)
    50  - [Additional Details](#additional-details)
    51    - [Test Plan [optional]](#test-plan-optional)
    52    - [Graduation Criteria [optional]](#graduation-criteria-optional)
    53    - [Version Skew Strategy [optional]](#version-skew-strategy-optional)
    54  - [Implementation History](#implementation-history)
    55  
    56  <!-- END doctoc generated TOC please keep comment here to allow auto update -->
    57  
    58  ## Glossary
    59  
    60  Refer to the [Cluster API Book Glossary](https://cluster-api.sigs.k8s.io/reference/glossary.html).
    61  
    62  Condition: The state of an object with regard to its appearance, quality, or working order.
    63  
    64  ## Summary
    65  
    66  In Cluster API a workload cluster is composed of a fair number of Kubernetes objects, and to
    67  understand the status of your Cluster you have to jump from one object to another. Or, in the
    68  worst case, you have to look at the logs from the Cluster API pods to get more details on why
    69  things aren’t working.
    70  
    71  This proposal introduces the concept of “conditions” as a tool designed to provide an “at a glance”
    72  view of the status of a cluster, providing immediate answers and fine-grained guidance when
    73  investigating issues. 
    74  
    75  ## Motivation
    76  
    77  - Cluster API requires a large number of objects to define a workload cluster: Cluster,
    78    InfrastructureCluster, KubeadmControlPlane, MachineDeployments, Machines, and so on.
    79    Each object carries its own status. Operators need to describe each object individually to
    80    determine an overall cluster health summary.
    81  - Objects can be tied to each other directly (via object references), or indirectly
    82    (via owner references). These dependencies can often require a deep knowledge of the
    83    project’s internals and its APIs to investigate issues or problems. 
    84  - Some objects, like MachineSets or MachineDeployments, are considered a collection of
    85    other objects (e.g. MachineSets). Their status is effectively tied to the status of each
    86    item in the collection. 
    87  
    88  ### Goals
    89  
    90  - To define a data model for the Condition type.
    91  - To introduce the first set of conditions on Cluster API core objects (up to a minimal level of
    92    detail required for an initial implementation).
    93  - To provide flexibility for providers to incrementally adopt this proposal.
    94  - To provide flexibility for providers to add, remove, or update their own set of conditions over time.
    95  - To provide utilities and libraries for a unified way to work with conditions.
    96  
    97  ### Non-Goals/Future Work
    98  
    99  - To pre-define every possible condition.
   100  - To define the exact semantic for every condition introduced in the proposal (this should be done
   101    during implementation).
   102  - To remove or deprecate `Phase`, `FailureMessage`, and `FailureReason` from Status in v0.3.
   103  - To remove or deprecate usage of `Events`.
   104  
   105  ## Proposal
   106  
   107  ### User Stories
   108  
   109  #### Story 1
   110  As a developer, as a user, as a tool built on top of Cluster API, I would like to have common types
   111  for defining conditions on different Cluster API or provider objects.
   112  
   113  #### Story 2        
   114  As a user, I would like to quickly understand the current state of my cluster
   115  during the initial provisioning workflow.
   116  
   117  #### Story 3
   118  As a user, I would like to quickly understand the current state of my cluster
   119  during the upgrade workflow.
   120  
   121  #### Story 4
   122  As a user, I would like to quickly understand the operational state of my cluster.
   123  
   124  ### Implementation Details/Notes/Constraints
   125  
   126  This proposal aims to be consistent with the target state of conditions in Kubernetes (see [KEP](https://github.com/kubernetes/enhancements/pull/1624)).
   127  
   128  At the same time, we should think that Cluster API presents some specific challenges that are not common
   129  to the core Kubernetes objects:
   130  
   131  - Cluster API has a high number of long-running operations, and this makes it crucial for the success of
   132    this proposal to introduce a clean way to provide evidence about what is happening during those operations,
   133    and not only to show the final state of the operations.
   134  - Cluster API has a complex hierarchy of objects, and the informative value of a condition, especially in
   135    the core types, is highly correlated to the possibility to collect and summarize meaningful information
   136    from the underlying hierarchy of objects.
   137  - Cluster API defines a set of core objects and extension points (e.g. bootstrap, control plane and infrastructure).
   138    Extension points are defined by a set of contracts, which each provider adheres to. To provide a great user
   139    experience, core and provider contracts should be extended to allow for better coordination and visibility
   140    based on conditions.
   141  
   142  
   143  This proposal consists of three parts:
   144  
   145  - Data model changes.
   146  - Constraints/design principles for implementing conditions in Cluster API-
   147  - Use case driven examples of how conditions could improve observability on Cluster API.
   148  
   149  #### Data Model Changes
   150  
   151  In this section we outline the proposed API additions.
   152  
   153  All the changes can be implemented in the v0.3.x timeframe (no breaking changes, only additions).
   154  
   155  Following types should be defined in Cluster API / v1alpha3 api.
   156  
   157  ```golang
   158  // ConditionType is a valid value for Condition.Type.
   159  type ConditionType string
   160  
   161  // ConditionSeverity expresses the severity of a Condition Type failing.
   162  type ConditionSeverity string
   163  
   164  const (
   165    // ConditionSeverityError specifies that a failure of a condition type
   166    // should be viewed as an error.
   167    ConditionSeverityError ConditionSeverity = "Error"
   168  
   169    // ConditionSeverityWarning specifies that a failure of a condition type
   170    // should be viewed as a warning, but that things could still work.
   171    ConditionSeverityWarning ConditionSeverity = "Warning"
   172  
   173    // ConditionSeverityInfo specifies that a failure of a condition type
   174    // should be viewed as purely informational, and that things could still work.
   175    ConditionSeverityInfo ConditionSeverity = "Info"
   176  
   177    // ConditionSeverityNone should apply only if the condition is in state "True".
   178    // As ConditionSeverityNone is the default for conditions we use the empty string (coupled with omitempty)
   179    ConditionSeverityNone ConditionSeverity = ""
   180  )
   181  
   182  // Condition defines an extension to status (i.e. an observation) of a Cluster API resource.
   183  type Condition struct {
   184     // Type of condition.
   185     Type ConditionType `json:"type" description:"type of status condition"`
   186  
   187     // Status of the condition, one of True, False, Unknown.
   188     Status corev1.ConditionStatus `json:"status"`
   189  
   190     // Severity with which to treat failures of this type of condition.
   191     // When this is not specified, it defaults to Error.
   192     // +optional
   193     Severity ConditionSeverity `json:"severity,omitempty"`
   194  
   195     // LastTransitionTime is the last time the condition transitioned from one status to another.
   196     LastTransitionTime metav1.Time `json:"lastTransitionTime"`
   197  
   198     // The reason for the condition's last transition.
   199     // Reasons should be CamelCase.
   200     // +optional
   201     Reason string `json:"reason,omitempty" description:"one-word CamelCase reason for the condition's last transition"`
   202  
   203     // A human readable message indicating details about the transition.
   204     // +optional
   205     Message string `json:"message,omitempty" description:"human-readable message indicating details about last transition"`
   206  }
   207  
   208  // Conditions define an extension to status (i.e. an observation) of a Cluster API resource.
   209  type Conditions []Condition
   210  ```
   211  
   212  Every Cluster API resource except data-only objects which aren't reconciled (i.e. `KubeadmConfigTemplate`)
   213  SHOULD have conditions field in the status struct. e.g.
   214  
   215  ```golang
   216  // ClusterStatus represent the status for the Cluster object
   217  type ClusterStatus struct {
   218      ...
   219      // Conditions define a list of readiness conditions for the Cluster object
   220      Conditions Conditions `json:"conditions,omitempty"
   221  } 
   222  ```
   223  
   224  Each Cluster API resource SHOULD define its own set of condition types, e.g. 
   225  
   226  ```golang
   227  // ConditionTypes for the cluster object 
   228  const (
   229  	ClusterInfrastructureReady ConditionType = "ClusterInfrastructureReady"
   230  	
   231  	...
   232  )
   233  ```
   234  
   235  Condition types MUST have a consistent polarity (i.e. "True = good");
   236  
   237  Condition types SHOULD have one of the following suffix:
   238  
   239  - `Ready`, for resources which represent an ongoing status, like `ControlplaneReady` or `MachineDeploymentsReady`.
   240  - `Succeeded`, for resources which run-to-completion, e.g. `CreateVPCSucceeded`
   241  
   242  When the above suffix are not adequate for a specific condition type, other suffix _with positive meaning_ COULD be used 
   243  (e.g. `Completed`, `Healthy`); however, it is recommended to balance this flexibility with the objective to provide
   244  a consistent condition naming across all the Cluster API objects.
   245  
   246  The `Severity` field MUST be set only when `Status=False` and it is designed to provide a standard classification
   247  of possible conditions failure `Reason`. 
   248  
   249  Please note that the combination of `Reason` and `Severity` gives different meaning to a condition failure
   250  allowing to detect when a long-running task is still ongoing:
   251  
   252  ```
   253  ControlPlaneReady=False, Reason=ScalingUp, Severity=Info
   254  ```
   255  
   256  In other cases, the combination of `Reason` and `Severity` allows to detect when a failure is due to a catastrophic
   257  error or to other events that are transient or can be eventually remediated by a user intervention
   258  
   259  ```
   260  MachineReady=False, Reason=MachineNotHealthy, Severity=Error
   261  MachineReady=False, Reason=MachineUnderProbation, Severity=Warning
   262  AWSMachineReady=False, Reason=SSHKeyMissing, Severity=Warning
   263  ```
   264  
   265  A more contextualized example/explanation about the Severity field can be found in the
   266  “Cluster provisioning” example later on in this document.
   267  
   268  #### Constraints
   269  In order to ensure a consistent implementation of conditions across all the Cluster API components
   270  the following constraints/design principles MUST be applied:
   271  
   272  ##### Condition semantic
   273  
   274  - Condition types in Cluster API core objects MUST be provider agnostic. 
   275  - Condition types in Cluster API core objects MUST represent the operational state of a component
   276    in the cluster, where the operational state is when the component is ready to serve application workloads. It should be avoided to represent only the infrastructure/provision part of the component's lifecycle.
   277  - Condition types in Cluster API provider-specific objects COULD be used for surfacing more
   278    granular/internal details about provisioning, but always with a user driven perspective (conditions != debug).
   279  - Operations like upgrades, scaling-up, or scaling-down, even if orchestrated in a non-disruptive fashion,
   280    MUST be considered as a deviation from the normal operational state of the cluster, and the operator
   281    should be always informed when those changes are happening. 
   282    e.g. There should be a condition with Severity=Warning.
   283  
   284  ##### The Ready condition
   285  
   286  - A `Ready` condition SHOULD be provided at object level to represent _the overall_ operational state of
   287    the component (NB. a more contextualized example/explanation of the Ready conditions can be found
   288    in the “Cluster provisioning” example later on in this document).
   289  - The `Ready` condition MUST be based on the summary of more detailed conditions existing on the same
   290    object, if defined. 
   291    e.g. `AWSCluster.Status.Conditions[Ready]` condition should be the summary of `VPCReady`, `SubnetsReady`,
   292    `InternetGatewaysReady` conditions.
   293  - Detailed conditions at object level COULD be based on `Ready` conditions gathered from the dependent
   294    objects. e.g. 
   295    - `Cluster.Status.Conditions[ClusterInfrastructureReady]` is a condition based on infrastructure
   296    cluster state, e.g. `AWSCluster.Status.Conditions[Ready]`. 
   297    - `KubeadmControlPlane.Status.Conditions[MachinesReady]` is a condition based on the aggregation
   298    of the underlying `Machines.Status.Conditions[Ready]` conditions.
   299  - A corollary of the above set of constraints is that an object SHOULD NEVER be in status `Ready=True`
   300    if one of the object's conditions are `false` or if one of the object dependents is in status `Ready=False`.
   301  
   302  ##### Controller changes
   303  
   304  - A controller MUST only evaluate Conditions based on the object it’s reconciling and its directly-referenced
   305    objects (dependents).
   306  - If the dependents objects are not exposing a `Ready` condition, the summary
   307    condition MUST NOT be generated and error MUST NOT be raised; please note that this approach (silently fail),
   308    is explicitly designed to allow an incremental implementation of conditions across providers; however,
   309    we are expecting this will change in the future.
   310  - In order to support an easy and consistent implementation of all the above constraints across all
   311    Cluster API components, all the controller MUST use a new set of utilities implemented in Cluster API for:
   312    - Summarizing a list of conditions into another condition on the same object
   313    - Mirroring a condition from an object to another.
   314    - Aggregating a condition from a set of dependents objects.
   315  
   316  #### The cluster provisioning workflow
   317  Let’s consider the following timeline representing the workflow for the initial provisioning of a
   318  Cluster with ClusterAPI:
   319  
   320  ![components](images/conditions/cluster-provision-workflow.png)
   321  
   322  Conditions are expected to provide a simple and intuitive view of where a Cluster is with respect
   323  to this timeline. 
   324  
   325  In order to do so, `Cluster.Status.Conditions` should have:
   326  
   327  - A condition of type `ClusterInfrastructureReady` that should provide an observation point on the
   328    operational state of the cluster infrastructure.
   329  - A condition of type `ControlPlaneReady` that should provide an observation point on the operational
   330    state of the cluster control plane.
   331  - A condition of type `WorkersReady` that should provide an observation point on the operational state
   332    of the workers nodes.
   333  
   334  ##### The `ClusterInfrastructureReady` condition
   335  In order to understand how `ClusterInfrastructureReady` condition can be, let’s take AWS as an example
   336  of how the cluster infrastructure process can be:
   337  
   338  - Provision Network
   339    - Provision VPC
   340    - Provision Subnets
   341    - Provision InternetGateways
   342    - ProvisionNatGateways
   343    - Provision RouteTables
   344    - Provision SecurityGroups
   345  - Provision Bastion Host
   346  - Etc.
   347  
   348  Without getting into further details, clearly provisioning an operational cluster infrastructure can
   349  be fairly complex, so we would expect to have in `AwsCluster.Status.Conditions` a set condition types
   350  providing observation points for all the above steps, e.g. `VPCReady`, `SubnetsReady`, 
   351  `InternetGatewaysReady`, etc.
   352  
   353  For all the above conditions `Status=True` corresponds to the final state when the resource is
   354  provisioned and fully operational (same polarity); it is also important to notice that the elapsed
   355  time when those conditions have `Status=False` can be fairly long, so it is crucial to introduce
   356  a clean way to provide evidence about what is happening during those phases, e.g.
   357  
   358  - The provisioning is just proceeding (info)
   359  - The provisioning is not completed yet, but it is taking longer than expected (warning)
   360  - A recoverable error occurred during provisioning and someone/something should take action (warning)
   361  - A catastrophic error occurred (error)
   362  - The provisioning is completed, but for any reason, the resource is not operational (error)
   363  
   364  This can be achieved by using different `Reason` and `Message` values, but this alone is not ideal, because,
   365  in order to understand the implications of each `Reason` code (is it info, a warning, or an error?),
   366  it might require a deep knowledge or provider internals; additionally, this forces condition consumers to
   367  depend on the `Reason` code enumeration, and this can lead to brittle solutions.
   368  
   369  This problem was addressed by the introduction of the `Severity` field, which provides an explicit
   370  classification of `Reason` code, so the users or machines can immediately understand the current situation
   371  and act accordingly.
   372  
   373  But, while having many provider-specific conditions in `AwsCluster.Status.Conditions` is definitely a
   374  remarkable improvement, at the same time this does not help in creating a consistent experience
   375  across providers, and it does not solve the problem of having a simple and intuitive view of the cluster
   376  infrastructure operational status in `Cluster.Status.Conditions`. 
   377  
   378  In order to solve this problem, the proposed solution is to:
   379  
   380  Introduce a `Ready` condition in `AwsCluster.Status.Conditions` that summarizes _the overall state_
   381  of the current operational status for a cluster infrastructure for AWS.
   382  
   383  Make the `ClusterInfrastructureReady` condition in `Cluster.Status.Conditions` to mirror the above
   384  one, or generalizing, to mirror the Ready condition from the infrastructure cluster object.
   385  
   386  Both actions can be generalized and implemented in utility in CAPI; as a working assumption, e.g.
   387  the utility that generates summary of a list of conditions should apply the following rules:
   388  - Errors MUST surface immediately. 
   389  - If there are no errors, Warnings MUST surface immediately.
   390  - The operation progress SHOULD be expressed in the form of step completed vs total steps to execute
   391    (details or possible alternatives TBD). 
   392  
   393  ##### The cluster’s `ControlPlaneReady` condition
   394  
   395  The condition of type `Cluster.Status.ControlPlaneReady` should provide an observation point on the
   396  operational state of the cluster control plane.
   397  
   398  In order to get this condition in place, we are re-applying the same design patterns defined in the
   399  previous paragraph and re-using the "Summarize" and the "Mirror" strategy across the hierarchy of
   400  objects that defines the cluster control plane. Below the description of all the required steps:
   401  
   402  A set of provider-specific conditions should be created in `AwsMachine.Status.Conditions`, e.g. 
   403  `InstanceReady`, `SecurityGroupsReady`, `LBAttachemenReady`, `BootstrapDataSecretDeletionSuccceded`
   404  (the other infrastructure providers are expected to implement different conditions at this level)
   405   
   406  A summary of the operational state of the machine infrastructure should be generated in
   407  `AwsMachine.Status.Conditions[Ready]`; this condition will be mirrored into
   408  `Machine.Status.Conditions[InfrastructureReady]`.
   409  
   410  A set of additional `Machine.Status.Conditions` should be created in order to provide an
   411  observation point on the operational state of kubeadm control-plane machine components like
   412  e.g. `EtcdReady`, `ApiServerPodReady`, etc. (the other control plane providers are expected to
   413  implement different conditions at this level)
   414  
   415  A summary of the operational state of the control plane machine should be generated into
   416  `Machine.Status.Conditions[Ready]`; the aggregation of all the machine’s Ready conditions will
   417  be mirrored into `KubeadmControlPlane.Status.Conditions[MachinesReady]`.
   418  
   419  A set of additional `KubeadmControlPlane.Status.Conditions` will be created in order
   420  to provide an observation point on the operational state of the overall kubeadm control-plane
   421  specific processes, like e.g. `ScalingUpSuccedeed`, `ScalingDownSuccedeed`, `MachineRemediationSuccedeed`. 
   422  
   423  A summary of the operational state of the entire control plane should be generated into
   424  `KubeadmControlPlane.Status.Conditions[Ready]`; this condition will be mirrored into 
   425  `Cluster.Status.Conditions[ControlPlaneReady]`.
   426  
   427  ##### The cluster’s `WorkersReady` condition
   428  
   429  The Cluster condition `Cluster.Status.WorkersReady` should provide an observation point on
   430  the operational state of all workers nodes (incl. Machines, MachineDeployments, MachineSets).
   431  
   432  This can be achieved using the same design patterns defined in the previous paragraph
   433  and re-using the "Summarize" and the "Mirror" strategy; however, in this case, the implementation should
   434  consider that a cluster can have many MachineDeployments, MachinePools, etc.
   435  
   436  Considering the complexity and to wait for more in-depth analysis and use-cases, the implementation
   437  of this Condition is deferred until a later stage.
   438  
   439  ### The control plane upgrade workflow
   440  
   441  To further validate the above design let’s consider another timeline representing the upgrade of a
   442  control plane:
   443  
   444  ![components](images/conditions/upgrade-workflow.png)
   445  
   446  Also in this case, we expect a simple and intuitive view of where a Cluster is with respect to this
   447  timeline, and we expect this should be provided by the condition of type `ControlPlaneReady`
   448  introduced in the previous paragraphs.
   449  
   450  However, in order to address the specific use case, the following conditions should be added
   451  to `KubeadmControlPlane.Status.Conditions`: `MachinesUpgradeSuccedeed`, `KubeProxyUpgradeSucceded`,
   452  `CoreDNSUpgradeSucceded`. Those conditions represent a “run-to-completion” task, and since all of
   453  them are related to the same upgrade process, we are assuming to reset those conditions every
   454  time an upgrade starts.
   455  
   456  Then, those new conditions will be then captured by the summary in `KubeadmControlPlane.Status.Conditions[Ready]`
   457  and be reflected to `Cluster.Status.Conditions[ControlPlaneReady]`.
   458  
   459  However, please note that during upgrades, some rules that are been used to evaluate the
   460  operational state of a control plane should be temporary changed e.g. during upgrades:
   461  
   462  - It is acceptable to have a number of replicas higher than the desired number of replicas
   463  - It is acceptable that one of the controlled machines is not fully operational while being provisioned.
   464  - It is acceptable that one of the controlled machines is becoming not operational while being deleted.
   465  
   466  During the implementation phase, we will consider if to treat such exceptions as a special case or if to
   467  enhance the condition utilities to handle those situations in a generalized way.
   468  
   469  ### Risks and Mitigations
   470  
   471  - Risk: This proposal aims to be consistent with the target state of conditions in Kubernetes, but this
   472    is still under definition (see [KEP](https://github.com/kubernetes/enhancements/pull/1624)).
   473    - Mitigation: Periodically re-evaluate this proposal vs the Kubernetes KEP. 
   474  
   475  - Risk: Cluster API presents some specific challenges that are not common to the core Kubernetes objects.
   476    - Mitigation: To allow a minimal set of carefully evaluated differences between Cluster API and Kubernetes
   477    conditions types.
   478    - Mitigation: To define constraints and to provide utilities for dealing with the Cluster API object hierarchy.
   479  
   480  - Risk: This proposal allows for implementing conditions in incremental fashion, and this makes it complex
   481    to ensure a consistent approach across all objects.
   482    - Mitigation: Ensure all the implementations comply with the defined set of constraints/design principles. 
   483  
   484  - Risk: Having a consistent polarity ensures a simple and clear contract with the consumers, and it allows 
   485    processing conditions in a simple and consistent way without being forced to implement specific logic
   486    for each condition type. However, we are aware about the fact that enforcing of consistent polarity (truthy)
   487    combined with the usage of recommended suffix for condition types can lead to verbal contortions to express 
   488    conditions, especially in case of conditions designed to signal problems or in case of conditions
   489    that might exist or not.
   490    - Mitigation: We are relaxing the rule about recommended suffix and allowing usage of custom suffix.
   491    - Mitigation: We are recommending the condition adhere to the design principle to express the operational state
   492      of the component, and this should help in avoiding conditions name to surface internal implementation details.
   493    - Mitigation: We should recommend condition implementers to clearly document the meaning of Unknown state, because as
   494      discussed also in the recent [Kubernetes KEP about standardizing conditions](https://github.com/kubernetes/enhancements/pull/1624#pullrequestreview-388777427),
   495      _"Unknown" is a fact about the writer of the condition, and not a claim about the object_.
   496    - Mitigation: We should recommend developers of code relying on conditions to treat Unknown as a separated state vs
   497      assimilating it to True or False, because this can vary case by case and generate confusion in readers.
   498      
   499    As a final consideration about the risk related to using a consistent polarity, it is important to notice that a
   500    consistent polarity ensure a clear meaning for True or o False states, which is already an improvement vs having
   501    different interpretations for all the three possible condition states.
   502    
   503  ## Alternatives
   504  
   505  ### Kubernetes Conditions
   506  
   507  While designing this proposal it was considered how Kubernetes APIs implements `.status.conditions` in different
   508  objects, i.e.
   509  
   510  Pods have a consistent set of conditions with positive polarity
   511  
   512  ```
   513   Type              Status
   514   Initialized       True
   515   Ready             True
   516   ContainersReady   True
   517   PodScheduled      True
   518  ```
   519  
   520  Nodes instead have a mix of negative and positive polarity conditions 
   521  
   522  ```
   523   Type             Status
   524   MemoryPressure   False
   525   DiskPressure     False
   526   PIDPressure      False
   527   Ready            True
   528  ```
   529  
   530  Not only the polarity, but also the schema of condition types slightly changes between different types, and in
   531  order to fix this, there is a [KEP](https://github.com/kubernetes/enhancements/pull/1624) that is trying to
   532  introduce a common Conditions type, as the first step for convergence about conditions usages and conditions
   533  types in Kubernetes.
   534  
   535  This proposal is moving along the same lines of the Kubernetes KEP, with the following small differences
   536  as of to day.
   537  
   538  - In K8s the `Type` field is a string, while in this proposal is a string alias so we can enforce the
   539    definition of a well-defined set of `ConditionType` constants.
   540  - In K8s there is an `ObservedGeneration` field, while in this proposal not.
   541  - In this proposal there is an `Severity` field for providing a better classification of the different
   542    reasons, while in this K8s not.
   543  
   544  ### Status field
   545  
   546  In Kubernetes during the discussions about conditions one of the points usually discussed is the possibility
   547  of using status fields instead of conditions.
   548  
   549  Within the context of this proposal, we are not considering this a viable option, mostly because status
   550  fields are object specific and this will fail the objective of creating a consistent UX for the users.
   551  
   552  ## Upgrade Strategy
   553  
   554  NA
   555  
   556  ## Additional Details
   557  
   558  ### Test Plan [optional]
   559  
   560  TBD
   561  
   562  ### Graduation Criteria [optional]
   563  
   564  TBD
   565  
   566  ### Version Skew Strategy [optional]
   567  
   568  NA
   569  
   570  ## Implementation History
   571  
   572  - [ ] 2020-04-27: Compile a Google Doc following the CAEP template
   573  - [ ] 2020-05-06: Create CAEP PR