Skip to content

Commit c2a2fb5

Browse files
committed
CONSOLE-3252: Create a ConsoleNotification when cluster is performing an upgrade
1 parent bd98a16 commit c2a2fb5

File tree

5 files changed

+201
-3
lines changed

5 files changed

+201
-3
lines changed

manifests/03-rbac-role-cluster.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ rules:
3535
- infrastructures
3636
- ingresses
3737
- proxies
38+
- clusterversions
3839
verbs:
3940
- get
4041
- list
@@ -69,6 +70,7 @@ rules:
6970
- console.openshift.io
7071
resources:
7172
- consoleclidownloads
73+
- consolenotifications
7274
verbs:
7375
- get
7476
- list

manifests/03-rbac-role-ns-operator.yaml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,15 @@ rules:
5454
verbs:
5555
- get
5656
- create
57-
- update
57+
- update
58+
- apiGroups:
59+
- console.openshift.io
60+
resources:
61+
- consolenotifications
62+
verbs:
63+
- get
64+
- list
65+
- watch
66+
- create
67+
- update
68+
- delete

pkg/api/api.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ package api
33
import "k8s.io/apimachinery/pkg/runtime/schema"
44

55
const (
6-
TargetNamespace = "openshift-console"
7-
ConfigResourceName = "cluster"
6+
TargetNamespace = "openshift-console"
7+
ConfigResourceName = "cluster"
8+
VersionResourceName = "version"
89
)
910

1011
// consts to maintain existing names of various sub-resources
@@ -59,6 +60,8 @@ const (
5960

6061
V1Alpha1PluginI18nAnnotation = "console.openshift.io/use-i18n"
6162

63+
UpgradeConsoleNotification = "cluster-upgrade"
64+
6265
NodeArchitectureLabel = "kubernetes.io/arch"
6366

6467
ManagedClusterViewAPIGroup = "view.open-cluster-management.io"
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
package upgradenotification
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
apierrors "k8s.io/apimachinery/pkg/api/errors"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/klog/v2"
11+
12+
v1 "github.com/openshift/api/config/v1"
13+
consolev1 "github.com/openshift/api/console/v1"
14+
operatorsv1 "github.com/openshift/api/operator/v1"
15+
configclientv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
16+
configinformer "github.com/openshift/client-go/config/informers/externalversions"
17+
configlistersv1 "github.com/openshift/client-go/config/listers/config/v1"
18+
consoleclientv1 "github.com/openshift/client-go/console/clientset/versioned/typed/console/v1"
19+
operatorclientv1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1"
20+
"github.com/openshift/console-operator/pkg/api"
21+
"github.com/openshift/console-operator/pkg/console/controllers/util"
22+
"github.com/openshift/console-operator/pkg/console/status"
23+
"github.com/openshift/library-go/pkg/controller/factory"
24+
"github.com/openshift/library-go/pkg/operator/events"
25+
"github.com/openshift/library-go/pkg/operator/v1helpers"
26+
)
27+
28+
// ctrl just needs the clients so it can make requests
29+
// the informers will automatically notify it of changes
30+
// and kick the sync loop
31+
type UpgradeNotificationController struct {
32+
operatorClient v1helpers.OperatorClient
33+
operatorConfigClient operatorclientv1.ConsoleInterface
34+
35+
consoleNotificationClient consoleclientv1.ConsoleNotificationInterface
36+
37+
// lister
38+
clusterVersionLister configlistersv1.ClusterVersionLister
39+
}
40+
41+
// factory func needs clients and informers
42+
// informers to start them up, clients to pass
43+
func NewUpgradeNotificationController(
44+
// top level config
45+
configClient configclientv1.ConfigV1Interface,
46+
configInformer configinformer.SharedInformerFactory,
47+
// clients
48+
operatorClient v1helpers.OperatorClient,
49+
operatorConfigClient operatorclientv1.ConsoleInterface,
50+
consoleNotificationClient consoleclientv1.ConsoleNotificationInterface,
51+
52+
recorder events.Recorder,
53+
) factory.Controller {
54+
55+
ctrl := &UpgradeNotificationController{
56+
operatorClient: operatorClient,
57+
operatorConfigClient: operatorConfigClient,
58+
consoleNotificationClient: consoleNotificationClient,
59+
clusterVersionLister: configInformer.Config().V1().ClusterVersions().Lister(),
60+
}
61+
62+
configV1Informers := configInformer.Config().V1()
63+
64+
return factory.New().
65+
WithFilteredEventsInformers( // configs
66+
util.IncludeNamesFilter(api.VersionResourceName),
67+
configV1Informers.ClusterVersions().Informer(),
68+
).ResyncEvery(time.Minute).WithSync(ctrl.Sync).
69+
ToController("ClusterUpgradeNotificationController", recorder.WithComponentSuffix("cluster-upgrade-notification-controller"))
70+
}
71+
72+
func (c *UpgradeNotificationController) Sync(ctx context.Context, controllerContext factory.SyncContext) error {
73+
operatorConfig, err := c.operatorConfigClient.Get(ctx, api.ConfigResourceName, metav1.GetOptions{})
74+
if err != nil {
75+
return err
76+
}
77+
updatedOperatorConfig := operatorConfig.DeepCopy()
78+
79+
switch updatedOperatorConfig.Spec.ManagementState {
80+
case operatorsv1.Managed:
81+
klog.V(4).Info("console-operator is in a managed state: syncing upgrade notification")
82+
case operatorsv1.Unmanaged:
83+
klog.V(4).Info("console-operator is in an unmanaged state: skipping upgrade notification sync")
84+
return nil
85+
case operatorsv1.Removed:
86+
klog.V(4).Info("console-operator is in a removed state: deleting upgrade notification")
87+
return c.removeUpgradeNotification(ctx)
88+
default:
89+
return fmt.Errorf("unknown state: %v", updatedOperatorConfig.Spec.ManagementState)
90+
}
91+
92+
statusHandler := status.NewStatusHandler(c.operatorClient)
93+
94+
reason, err := c.syncClusterUpgradeNotification(ctx)
95+
if err != nil {
96+
klog.V(4).Infof("error syncing %s consolenotification custom resource: %s", api.UpgradeConsoleNotification, err)
97+
statusHandler.AddConditions(status.HandleProgressingOrDegraded("ConsoleNotificationSync", reason, err))
98+
}
99+
return statusHandler.FlushAndReturn(err)
100+
}
101+
102+
func (c *UpgradeNotificationController) syncClusterUpgradeNotification(ctx context.Context) (string, error) {
103+
clusterVersionConfig, err := c.clusterVersionLister.Get(api.VersionResourceName)
104+
if err != nil {
105+
return "FailedGetClusterVersion", err
106+
}
107+
108+
isUpdateProgressing := getClusterVersionCondition(*clusterVersionConfig, v1.ConditionTrue, v1.OperatorProgressing)
109+
110+
if isUpdateProgressing {
111+
var currentVersion string
112+
for _, version := range clusterVersionConfig.Status.History {
113+
if version.State == v1.CompletedUpdate {
114+
currentVersion = version.Version
115+
break
116+
}
117+
}
118+
desiredVersion := clusterVersionConfig.Status.Desired.Version
119+
120+
if currentVersion == desiredVersion {
121+
return "", nil
122+
}
123+
124+
notification := &consolev1.ConsoleNotification{
125+
ObjectMeta: metav1.ObjectMeta{
126+
Name: api.UpgradeConsoleNotification,
127+
},
128+
Spec: consolev1.ConsoleNotificationSpec{
129+
Text: fmt.Sprintf("This cluster is updating from %s to %s", currentVersion, desiredVersion),
130+
Location: "BannerTop",
131+
Color: "#FFFFFF",
132+
BackgroundColor: "#F0AB00",
133+
},
134+
}
135+
_, err = c.consoleNotificationClient.Create(ctx, notification, metav1.CreateOptions{})
136+
if err != nil && !apierrors.IsAlreadyExists(err) {
137+
return "FailedCreate", err
138+
}
139+
} else {
140+
err = c.removeUpgradeNotification(ctx)
141+
if err != nil {
142+
return "FailedDelete", err
143+
}
144+
}
145+
146+
return "", nil
147+
}
148+
149+
func (c *UpgradeNotificationController) removeUpgradeNotification(ctx context.Context) error {
150+
err := c.consoleNotificationClient.Delete(ctx, api.UpgradeConsoleNotification, metav1.DeleteOptions{})
151+
if !apierrors.IsNotFound(err) {
152+
klog.V(4).Infof("error deleting %s consolenotification custom resource: %s", api.UpgradeConsoleNotification, err)
153+
return err
154+
}
155+
return nil
156+
}
157+
158+
func getClusterVersionCondition(cvo v1.ClusterVersion, conditionStatus v1.ConditionStatus, conditionType v1.ClusterStatusConditionType) bool {
159+
isConditionFulfilled := false
160+
for _, condition := range cvo.Status.Conditions {
161+
if condition.Status == conditionStatus && condition.Type == conditionType {
162+
isConditionFulfilled = true
163+
break
164+
}
165+
}
166+
167+
return isConditionFulfilled
168+
}

pkg/console/starter/starter.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
pdb "github.com/openshift/console-operator/pkg/console/controllers/poddisruptionbudget"
2929
"github.com/openshift/console-operator/pkg/console/controllers/route"
3030
"github.com/openshift/console-operator/pkg/console/controllers/service"
31+
upgradenotification "github.com/openshift/console-operator/pkg/console/controllers/upgradenotification"
3132
"github.com/openshift/console-operator/pkg/console/operatorclient"
3233
"github.com/openshift/library-go/pkg/controller/controllercmd"
3334
"github.com/openshift/library-go/pkg/operator/managementstatecontroller"
@@ -352,6 +353,18 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
352353
recorder,
353354
)
354355

356+
upgradeNotificationController := upgradenotification.NewUpgradeNotificationController(
357+
// top level config
358+
configClient.ConfigV1(),
359+
configInformers,
360+
// clients
361+
operatorClient,
362+
operatorConfigClient.OperatorV1().Consoles(),
363+
consoleClient.ConsoleV1().ConsoleNotifications(),
364+
//events
365+
recorder,
366+
)
367+
355368
versionRecorder := status.NewVersionGetter()
356369
versionRecorder.SetVersion("operator", os.Getenv("RELEASE_VERSION"))
357370

@@ -469,6 +482,7 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
469482
consoleRouteHealthCheckController,
470483
consolePDBController,
471484
downloadsPDBController,
485+
upgradeNotificationController,
472486
staleConditionsController,
473487
} {
474488
go controller.Run(ctx, 1)

0 commit comments

Comments
 (0)