Skip to content

Commit 181aafb

Browse files
committed
refactor(subs): add objectreference installplan refs
- Add objectreference installplan refs - Cleanup fake operator configuration - Surface fake client configurations
1 parent 6712b0d commit 181aafb

File tree

6 files changed

+326
-102
lines changed

6 files changed

+326
-102
lines changed

pkg/api/apis/operators/v1alpha1/subscription_types.go

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package v1alpha1
22

33
import (
4+
corev1 "k8s.io/api/core/v1"
45
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
56
"k8s.io/apimachinery/pkg/types"
67
)
@@ -36,24 +37,34 @@ type SubscriptionSpec struct {
3637
InstallPlanApproval Approval `json:"installPlanApproval,omitempty"`
3738
}
3839

39-
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
40-
// +genclient
41-
type Subscription struct {
42-
metav1.TypeMeta `json:",inline"`
43-
metav1.ObjectMeta `json:"metadata"`
40+
type SubscriptionStatus struct {
41+
// CurrentCSV is the CSV the Subscription is progressing to.
42+
// +optional
43+
CurrentCSV string `json:"currentCSV,omitempty"`
4444

45-
Spec *SubscriptionSpec `json:"spec"`
46-
Status SubscriptionStatus `json:"status"`
47-
}
45+
// InstalledCSV is the CSV currently installed by the Subscription.
46+
// +optional
47+
InstalledCSV string `json:"installedCSV,omitempty"`
4848

49-
type SubscriptionStatus struct {
50-
CurrentCSV string `json:"currentCSV,omitempty"`
51-
InstalledCSV string `json:"installedCSV, omitempty"`
52-
Install *InstallPlanReference `json:"installplan,omitempty"`
49+
// Install is a reference to the latest InstallPlan generated for the Subscription.
50+
// DEPRECATED: InstallPlanRef
51+
// +optional
52+
Install *InstallPlanReference `json:"installplan,omitempty"`
53+
54+
// State represents the current state of the Subscription
55+
// +optional
56+
State SubscriptionState `json:"state,omitempty"`
57+
58+
// Reason is the reason the Subscription was transitioned to its current state.
59+
// +optional
60+
Reason ConditionReason `json:"reason,omitempty"`
61+
62+
// InstallPlanRef is a reference to the latest InstallPlan that contains the Subscription's current CSV.
63+
// +optional
64+
InstallPlanRef *corev1.ObjectReference `json:"installPlanRef,omitempty"`
5365

54-
State SubscriptionState `json:"state,omitempty"`
55-
Reason ConditionReason `json:"reason,omitempty"`
56-
LastUpdated metav1.Time `json:"lastUpdated"`
66+
// LastUpdated represents the last time that the Subscription status was updated.
67+
LastUpdated metav1.Time `json:"lastUpdated"`
5768
}
5869

5970
type InstallPlanReference struct {
@@ -63,6 +74,16 @@ type InstallPlanReference struct {
6374
UID types.UID `json:"uuid"`
6475
}
6576

77+
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
78+
// +genclient
79+
type Subscription struct {
80+
metav1.TypeMeta `json:",inline"`
81+
metav1.ObjectMeta `json:"metadata"`
82+
83+
Spec *SubscriptionSpec `json:"spec"`
84+
Status SubscriptionStatus `json:"status"`
85+
}
86+
6687
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
6788
type SubscriptionList struct {
6889
metav1.TypeMeta `json:",inline"`
@@ -78,3 +99,13 @@ func (s *Subscription) GetInstallPlanApproval() Approval {
7899
}
79100
return ApprovalAutomatic
80101
}
102+
103+
// NewInstallPlanReference returns an InstallPlanReference for the given ObjectReference.
104+
func NewInstallPlanReference(ref *corev1.ObjectReference) *InstallPlanReference {
105+
return &InstallPlanReference{
106+
APIVersion: ref.APIVersion,
107+
Kind: ref.Kind,
108+
Name: ref.Name,
109+
UID: ref.UID,
110+
}
111+
}

pkg/api/apis/operators/v1alpha1/zz_generated.deepcopy.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Copyright 2019 Red Hat, Inc.
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+
package fake
17+
18+
import (
19+
"k8s.io/apimachinery/pkg/runtime"
20+
"k8s.io/client-go/testing"
21+
)
22+
23+
// ClientsetDecorator defines decorator methods for a Clientset.
24+
type ClientsetDecorator interface {
25+
// PrependReactor adds a reactor to the beginning of the chain.
26+
PrependReactor(verb, resource string, reaction testing.ReactionFunc)
27+
}
28+
29+
// ReactionForwardingClientsetDecorator wraps a Clientset and "forwards" Action object mutations
30+
// from all successful non-handling Reactors along the chain to the first handling Reactor. This is
31+
// is a stopgap until we can upgrade to client-go v11.0, where the behavior is the default
32+
// (see https://github.com/kubernetes/client-go/blob/6ee68ca5fd8355d024d02f9db0b3b667e8357a0f/testing/fake.go#L130).
33+
type ReactionForwardingClientsetDecorator struct {
34+
Clientset
35+
ReactionChain []testing.Reactor // shadow embedded ReactionChain
36+
actions []testing.Action // these may be castable to other types, but "Action" is the minimum
37+
}
38+
39+
// NewReactionForwardingClientsetDecorator returns the ReactionForwardingClientsetDecorator wrapped Clientset result
40+
// of calling NewSimpleClientset with the given objects.
41+
func NewReactionForwardingClientsetDecorator(objects ...runtime.Object) *ReactionForwardingClientsetDecorator {
42+
decorator := &ReactionForwardingClientsetDecorator{
43+
Clientset: *NewSimpleClientset(objects...),
44+
}
45+
46+
// Swap out the embedded ReactionChain with a Reactor that reduces over the decorator's ReactionChain.
47+
decorator.ReactionChain = decorator.Clientset.ReactionChain
48+
decorator.Clientset.ReactionChain = []testing.Reactor{&testing.SimpleReactor{"*", "*", decorator.reduceReactions}}
49+
50+
return decorator
51+
}
52+
53+
// reduceReactions reduces over all reactions in the chain while "forwarding" Action object mutations
54+
// from all successful non-handling Reactors along the chain to the first handling Reactor.
55+
func (c *ReactionForwardingClientsetDecorator) reduceReactions(action testing.Action) (handled bool, ret runtime.Object, err error) {
56+
// The embedded Client set is already locked, so there's no need to lock again
57+
actionCopy := action.DeepCopy()
58+
c.actions = append(c.actions, action.DeepCopy())
59+
for _, reactor := range c.ReactionChain {
60+
if !reactor.Handles(actionCopy) {
61+
continue
62+
}
63+
64+
handled, ret, err = reactor.React(actionCopy)
65+
if !handled {
66+
continue
67+
}
68+
69+
return
70+
}
71+
72+
return
73+
}
74+
75+
// PrependReactor adds a reactor to the beginning of the chain.
76+
func (c *ReactionForwardingClientsetDecorator) PrependReactor(verb, resource string, reaction testing.ReactionFunc) {
77+
c.ReactionChain = append([]testing.Reactor{&testing.SimpleReactor{verb, resource, reaction}}, c.ReactionChain...)
78+
}

pkg/controller/operators/catalog/operator.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"k8s.io/client-go/tools/cache"
2626
"k8s.io/client-go/util/workqueue"
2727

28+
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators"
2829
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
2930
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client"
3031
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
@@ -595,11 +596,11 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error {
595596
})
596597

597598
// ensure the installplan reference is correct
598-
sub, changedIp, err := o.ensureSubscriptionInstallPlanState(logger, sub)
599+
sub, changedIP, err := o.ensureSubscriptionInstallPlanState(logger, sub)
599600
if err != nil {
600601
return err
601602
}
602-
subscriptionUpdated = subscriptionUpdated || changedIp
603+
subscriptionUpdated = subscriptionUpdated || changedIP
603604

604605
// record the current state of the desired corresponding CSV in the status. no-op if we don't know the csv yet.
605606
sub, changedCSV, err := o.ensureSubscriptionCSVState(logger, sub, querier)
@@ -756,8 +757,15 @@ func (o *Operator) ensureSubscriptionInstallPlanState(logger *logrus.Entry, sub
756757
logger.WithField("installplan", ipName).Debug("found installplan that generated subscription")
757758

758759
out := sub.DeepCopy()
759-
out.Status.Install = o.referenceForInstallPlan(ip)
760+
ref, err := operators.GetReference(ip)
761+
if err != nil {
762+
logger.WithError(err).Warn("unable to generate installplan reference")
763+
return nil, false, err
764+
}
765+
out.Status.InstallPlanRef = ref
766+
out.Status.Install = v1alpha1.NewInstallPlanReference(ref)
760767
out.Status.State = v1alpha1.SubscriptionStateUpgradePending
768+
761769
updated, err := o.client.OperatorsV1alpha1().Subscriptions(sub.GetNamespace()).UpdateStatus(out)
762770
if err != nil {
763771
return nil, false, err
@@ -807,13 +815,14 @@ func (o *Operator) ensureSubscriptionCSVState(logger *logrus.Entry, sub *v1alpha
807815
return sub, true, nil
808816
}
809817

810-
func (o *Operator) updateSubscriptionStatus(namespace string, subs []*v1alpha1.Subscription, installPlanRef *v1alpha1.InstallPlanReference) error {
818+
func (o *Operator) updateSubscriptionStatus(namespace string, subs []*v1alpha1.Subscription, installPlanRef *corev1.ObjectReference) error {
811819
// TODO: parallel, sync waitgroup
812820
var err error
813821
for _, sub := range subs {
814822
sub.Status.LastUpdated = timeNow()
815823
if installPlanRef != nil {
816-
sub.Status.Install = installPlanRef
824+
sub.Status.InstallPlanRef = installPlanRef
825+
sub.Status.Install = v1alpha1.NewInstallPlanReference(installPlanRef)
817826
sub.Status.State = v1alpha1.SubscriptionStateUpgradePending
818827
}
819828
if _, subErr := o.client.OperatorsV1alpha1().Subscriptions(namespace).UpdateStatus(sub); subErr != nil {
@@ -823,7 +832,7 @@ func (o *Operator) updateSubscriptionStatus(namespace string, subs []*v1alpha1.S
823832
return err
824833
}
825834

826-
func (o *Operator) ensureInstallPlan(logger *logrus.Entry, namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step) (*v1alpha1.InstallPlanReference, error) {
835+
func (o *Operator) ensureInstallPlan(logger *logrus.Entry, namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step) (*corev1.ObjectReference, error) {
827836
if len(steps) == 0 {
828837
return nil, nil
829838
}
@@ -837,15 +846,15 @@ func (o *Operator) ensureInstallPlan(logger *logrus.Entry, namespace string, sub
837846
for _, installPlan := range installPlans {
838847
if installPlan.Status.CSVManifestsMatch(steps) {
839848
logger.Infof("found InstallPlan with matching manifests: %s", installPlan.GetName())
840-
return o.referenceForInstallPlan(installPlan), nil
849+
return operators.GetReference(installPlan)
841850
}
842851
}
843852
logger.Warn("no installplan found with matching manifests, creating new one")
844853

845854
return o.createInstallPlan(namespace, subs, installPlanApproval, steps)
846855
}
847856

848-
func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step) (*v1alpha1.InstallPlanReference, error) {
857+
func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscription, installPlanApproval v1alpha1.Approval, steps []*v1alpha1.Step) (*corev1.ObjectReference, error) {
849858
if len(steps) == 0 {
850859
return nil, nil
851860
}
@@ -896,17 +905,8 @@ func (o *Operator) createInstallPlan(namespace string, subs []*v1alpha1.Subscrip
896905
if err != nil {
897906
return nil, err
898907
}
899-
return o.referenceForInstallPlan(res), nil
900908

901-
}
902-
903-
func (o *Operator) referenceForInstallPlan(ip *v1alpha1.InstallPlan) *v1alpha1.InstallPlanReference {
904-
return &v1alpha1.InstallPlanReference{
905-
UID: ip.GetUID(),
906-
Name: ip.GetName(),
907-
APIVersion: v1alpha1.SchemeGroupVersion.String(),
908-
Kind: v1alpha1.InstallPlanKind,
909-
}
909+
return operators.GetReference(res)
910910
}
911911

912912
func (o *Operator) requeueSubscription(name, namespace string) {

0 commit comments

Comments
 (0)