generated from vshn/go-bootstrap
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add controller which reports K8s and OCP version to control-api
The controller reconciles clusterversion.config.openshift.io which should be sufficient to detect changes in the K8s/OCP version.
- Loading branch information
Showing
2 changed files
with
178 additions
and
5 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
package controllers | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"strings" | ||
"time" | ||
"unicode" | ||
|
||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/log" | ||
|
||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/version" | ||
"k8s.io/client-go/rest" | ||
"k8s.io/client-go/tools/record" | ||
|
||
controlv1 "github.com/appuio/control-api/apis/v1" | ||
configv1 "github.com/openshift/api/config/v1" | ||
|
||
"go.uber.org/multierr" | ||
) | ||
|
||
type ZoneK8sVersionReconciler struct { | ||
client.Client | ||
Scheme *runtime.Scheme | ||
Recorder record.EventRecorder | ||
|
||
ForeignClient client.Client | ||
RESTClient rest.Interface | ||
|
||
// upstream zone ID. The agent expects that the control-api zone | ||
// object is labeled with | ||
ZoneID string | ||
} | ||
|
||
const ( | ||
upstreamZoneIdentifierLabelKey = "control.appuio.io/zone-cluster-id" | ||
kubernetesVersionFeatureKey = "kubernetesVersion" | ||
openshiftVersionFeatureKey = "openshiftVersion" | ||
) | ||
|
||
func extractOpenShiftVersion(cv *configv1.ClusterVersion) string { | ||
currentVersion := "" | ||
lastUpdate := time.Time{} | ||
for _, h := range cv.Status.History { | ||
if h.State == "Completed" && h.Verified == true && h.CompletionTime.Time.After(lastUpdate) { | ||
currentVersion = h.Version | ||
lastUpdate = h.CompletionTime.Time | ||
} | ||
} | ||
if currentVersion == "" { | ||
return cv.Status.Desired.Version | ||
} | ||
return currentVersion | ||
} | ||
|
||
func extractK8sVersion(v *version.Info) (string, error) { | ||
major := trimVersion(v.Major) | ||
if major == "" { | ||
return "", fmt.Errorf("unknown major version %q", v.Major) | ||
} | ||
minor := trimVersion(v.Minor) | ||
if minor == "" { | ||
return "", fmt.Errorf("unknown minor version %q", v.Minor) | ||
} | ||
gitverparts := strings.Split(v.GitVersion, ".") | ||
patchV := strings.Split(gitverparts[2], "+")[0] | ||
patch := trimVersion(patchV) | ||
if patch == "" { | ||
return "", fmt.Errorf("unknown patch version %q", patchV) | ||
} | ||
return fmt.Sprintf("%s.%s.%s", major, minor, patch), nil | ||
} | ||
|
||
func trimVersion(v string) string { | ||
res := []rune{} | ||
for _, r := range v { | ||
if !unicode.IsDigit(r) { | ||
break | ||
} | ||
res = append(res, r) | ||
} | ||
return string(res) | ||
} | ||
|
||
// Reconcile reads the K8s and OCP versions and writes them to the upstream | ||
// zone | ||
func (r *ZoneK8sVersionReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
l := log.FromContext(ctx) | ||
l.Info("Reconciling zone K8s version") | ||
|
||
var cv = configv1.ClusterVersion{} | ||
if err := r.Client.Get(ctx, req.NamespacedName, &cv); err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
|
||
ocpVer := extractOpenShiftVersion(&cv) | ||
|
||
l.Info("OCP current version", "version", ocpVer) | ||
|
||
body, err := r.RESTClient.Get().AbsPath("/version").Do(ctx).Raw() | ||
if err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
var info version.Info | ||
err = json.Unmarshal(body, &info) | ||
if err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
k8sVer, err := extractK8sVersion(&info) | ||
if err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
|
||
l.Info("K8s current version", "version", k8sVer) | ||
|
||
var zones = controlv1.ZoneList{} | ||
if err := r.ForeignClient.List(ctx, &zones, client.MatchingLabels{upstreamZoneIdentifierLabelKey: r.ZoneID}); err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
var errs []error | ||
for _, z := range zones.Items { | ||
if k8sVer != "" { | ||
z.Data.Features[kubernetesVersionFeatureKey] = k8sVer | ||
} | ||
if ocpVer != "" { | ||
z.Data.Features[openshiftVersionFeatureKey] = ocpVer | ||
} | ||
if err := r.ForeignClient.Update(ctx, &z); err != nil { | ||
errs = append(errs, err) | ||
} | ||
} | ||
|
||
return ctrl.Result{}, multierr.Combine(errs...) | ||
} | ||
|
||
// SetupWithManager sets up the controller with the Manager. | ||
func (r *ZoneK8sVersionReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&configv1.ClusterVersion{}). | ||
Named("zone_k8s_version"). | ||
Complete(r) | ||
} |
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