Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add OLM support for the Upgradeable OperatorCondition
OLM will check for OperatorCondition CR for OperatorUpgradeable status. The pending CSV will not transition to Succeeded status until the operator is upgradeable based on the OperatorCondition. If the operator doesn't use OperatorCondition, the normal transition is expected. Cluster Admin will be able to override the OperatorUpgradeable condition. Add an e2e test for OperatorUpgradeable condition. OLM will check for replacedCSV's Upgradeable condition to ensure the new CSV is able to be upgraded. If the previous condition is False, the new CSV will stay in Pending to prevent the deployment to be installed. Signed-off-by: Vu Dinh <vdinh@redhat.com>
- Loading branch information
1 parent
cfda6a3
commit cb1fe22
Showing
11 changed files
with
533 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package olm | ||
|
||
import ( | ||
"fmt" | ||
|
||
k8serrors "k8s.io/apimachinery/pkg/api/errors" | ||
meta "k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
|
||
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" | ||
"github.com/operator-framework/api/pkg/operators/v1alpha1" | ||
) | ||
|
||
func (a *Operator) isOperatorUpgradeable(csv *v1alpha1.ClusterServiceVersion) (bool, error) { | ||
if csv == nil { | ||
return false, fmt.Errorf("CSV is invalid") | ||
} | ||
|
||
cond, err := a.lister.OperatorsV1().OperatorConditionLister().OperatorConditions(csv.GetNamespace()).Get(csv.GetName()) | ||
if err != nil { | ||
if k8serrors.IsNotFound(err) { | ||
return true, nil | ||
} | ||
return false, err | ||
} | ||
|
||
// Check condition overrides | ||
for _, override := range cond.Spec.Overrides { | ||
if override.Type == operatorsv1.OperatorUpgradeable { | ||
if override.Status == metav1.ConditionTrue { | ||
return true, nil | ||
} | ||
return false, fmt.Errorf("The operator is not upgradeable: %s", override.Message) | ||
} | ||
} | ||
|
||
// Check for OperatorUpgradeable condition status | ||
if c := meta.FindStatusCondition(cond.Status.Conditions, operatorsv1.OperatorUpgradeable); c != nil { | ||
if c.Status == metav1.ConditionFalse { | ||
return false, fmt.Errorf("The operator is not upgradeable: %s", c.Message) | ||
} | ||
} | ||
|
||
return true, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package operatorlister | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
|
||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/labels" | ||
"k8s.io/apimachinery/pkg/types" | ||
|
||
v1 "github.com/operator-framework/api/pkg/operators/v1" | ||
listers "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1" | ||
) | ||
|
||
type UnionOperatorConditionLister struct { | ||
opConditionListers map[string]listers.OperatorConditionLister | ||
opConditionLock sync.RWMutex | ||
} | ||
|
||
// List lists all OperatorConditions in the indexer. | ||
func (uol *UnionOperatorConditionLister) List(selector labels.Selector) (ret []*v1.OperatorCondition, err error) { | ||
uol.opConditionLock.RLock() | ||
defer uol.opConditionLock.RUnlock() | ||
|
||
set := make(map[types.UID]*v1.OperatorCondition) | ||
for _, cl := range uol.opConditionListers { | ||
csvs, err := cl.List(selector) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, csv := range csvs { | ||
set[csv.GetUID()] = csv | ||
} | ||
} | ||
|
||
for _, csv := range set { | ||
ret = append(ret, csv) | ||
} | ||
|
||
return | ||
} | ||
|
||
// OperatorConditions returns an object that can list and get OperatorConditions. | ||
func (uol *UnionOperatorConditionLister) OperatorConditions(namespace string) listers.OperatorConditionNamespaceLister { | ||
uol.opConditionLock.RLock() | ||
defer uol.opConditionLock.RUnlock() | ||
|
||
// Check for specific namespace listers | ||
if cl, ok := uol.opConditionListers[namespace]; ok { | ||
return cl.OperatorConditions(namespace) | ||
} | ||
|
||
// Check for any namespace-all listers | ||
if cl, ok := uol.opConditionListers[metav1.NamespaceAll]; ok { | ||
return cl.OperatorConditions(namespace) | ||
} | ||
|
||
return &NullOperatorConditionNamespaceLister{} | ||
} | ||
|
||
func (uol *UnionOperatorConditionLister) RegisterOperatorConditionLister(namespace string, lister listers.OperatorConditionLister) { | ||
uol.opConditionLock.Lock() | ||
defer uol.opConditionLock.Unlock() | ||
|
||
if uol.opConditionListers == nil { | ||
uol.opConditionListers = make(map[string]listers.OperatorConditionLister) | ||
} | ||
|
||
uol.opConditionListers[namespace] = lister | ||
} | ||
|
||
func (l *operatorsV1Lister) RegisterOperatorConditionLister(namespace string, lister listers.OperatorConditionLister) { | ||
l.operatorConditionLister.RegisterOperatorConditionLister(namespace, lister) | ||
} | ||
|
||
func (l *operatorsV1Lister) OperatorConditionLister() listers.OperatorConditionLister { | ||
return l.operatorConditionLister | ||
} | ||
|
||
// NullOperatorConditionNamespaceLister is an implementation of a null OperatorConditionNamespaceLister. It is | ||
// used to prevent nil pointers when no OperatorConditionNamespaceLister has been registered for a given | ||
// namespace. | ||
type NullOperatorConditionNamespaceLister struct { | ||
listers.OperatorConditionNamespaceLister | ||
} | ||
|
||
// List returns nil and an error explaining that this is a NullOperatorConditionNamespaceLister. | ||
func (n *NullOperatorConditionNamespaceLister) List(selector labels.Selector) (ret []*v1.OperatorCondition, err error) { | ||
return nil, fmt.Errorf("cannot list OperatorConditions with a NullOperatorConditionNamespaceLister") | ||
} | ||
|
||
// Get returns nil and an error explaining that this is a NullOperatorConditionNamespaceLister. | ||
func (n *NullOperatorConditionNamespaceLister) Get(name string) (*v1.OperatorCondition, error) { | ||
return nil, fmt.Errorf("cannot get OperatorCondition with a NullOperatorConditionNamespaceLister") | ||
} |
104 changes: 104 additions & 0 deletions
104
pkg/lib/operatorlister/operatorlisterfakes/fake_operators_v1lister.go
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.