Skip to content

Commit

Permalink
update api
Browse files Browse the repository at this point in the history
  • Loading branch information
ranakan19 committed Jun 27, 2024
2 parents 4bff8de + 7ec2869 commit 6e615a7
Show file tree
Hide file tree
Showing 28 changed files with 449 additions and 280 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/linters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
uses: actions/checkout@v4

- name: Lint
uses: golangci/golangci-lint-action@v5
uses: golangci/golangci-lint-action@v6
with:
version: v1.52.0
skip-pkg-cache: true
Expand Down
36 changes: 18 additions & 18 deletions controllers/toolchaincluster/healthchecker.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,50 +64,50 @@ func (hc *HealthChecker) getClusterHealthStatus(ctx context.Context) *toolchainv
return &clusterStatus
}

func clusterReadyCondition() toolchainv1alpha1.ToolchainClusterCondition {
func clusterReadyCondition() toolchainv1alpha1.Condition {
currentTime := metav1.Now()
return toolchainv1alpha1.ToolchainClusterCondition{
Type: toolchainv1alpha1.ToolchainClusterReady,
return toolchainv1alpha1.Condition{
Type: toolchainv1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
Reason: toolchainv1alpha1.ToolchainClusterClusterReadyReason,
Message: healthzOk,
LastProbeTime: currentTime,
LastTransitionTime: &currentTime,
LastUpdatedTime: &currentTime,
LastTransitionTime: currentTime,
}
}

func clusterNotReadyCondition() toolchainv1alpha1.ToolchainClusterCondition {
func clusterNotReadyCondition() toolchainv1alpha1.Condition {
currentTime := metav1.Now()
return toolchainv1alpha1.ToolchainClusterCondition{
Type: toolchainv1alpha1.ToolchainClusterReady,
return toolchainv1alpha1.Condition{
Type: toolchainv1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Reason: toolchainv1alpha1.ToolchainClusterClusterNotReadyReason,
Message: healthzNotOk,
LastProbeTime: currentTime,
LastTransitionTime: &currentTime,
LastUpdatedTime: &currentTime,
LastTransitionTime: currentTime,
}
}

func clusterOfflineCondition() toolchainv1alpha1.ToolchainClusterCondition {
func clusterOfflineCondition() toolchainv1alpha1.Condition {
currentTime := metav1.Now()
return toolchainv1alpha1.ToolchainClusterCondition{
return toolchainv1alpha1.Condition{
Type: toolchainv1alpha1.ToolchainClusterOffline,
Status: corev1.ConditionTrue,
Reason: toolchainv1alpha1.ToolchainClusterClusterNotReachableReason,
Message: clusterNotReachableMsg,
LastProbeTime: currentTime,
LastTransitionTime: &currentTime,
LastUpdatedTime: &currentTime,
LastTransitionTime: currentTime,
}
}

func clusterNotOfflineCondition() toolchainv1alpha1.ToolchainClusterCondition {
func clusterNotOfflineCondition() toolchainv1alpha1.Condition {
currentTime := metav1.Now()
return toolchainv1alpha1.ToolchainClusterCondition{
return toolchainv1alpha1.Condition{
Type: toolchainv1alpha1.ToolchainClusterOffline,
Status: corev1.ConditionFalse,
Reason: toolchainv1alpha1.ToolchainClusterClusterReachableReason,
Message: clusterReachableMsg,
LastProbeTime: currentTime,
LastTransitionTime: &currentTime,
LastUpdatedTime: &currentTime,
LastTransitionTime: currentTime,
}
}
40 changes: 20 additions & 20 deletions controllers/toolchaincluster/healthchecker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,59 +41,59 @@ func TestClusterHealthChecks(t *testing.T) {
tests := map[string]struct {
tctype string
apiendpoint string
clusterconditions []toolchainv1alpha1.ToolchainClusterCondition
clusterconditions []toolchainv1alpha1.Condition
status toolchainv1alpha1.ToolchainClusterStatus
}{
//ToolchainCluster.status doesn't contain any conditions
"UnstableNoCondition": {
tctype: "unstable",
apiendpoint: "http://unstable.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{unhealthy(), notOffline()},
clusterconditions: []toolchainv1alpha1.Condition{unhealthy(), notOffline()},
status: toolchainv1alpha1.ToolchainClusterStatus{},
},
"StableNoCondition": {
tctype: "stable",
apiendpoint: "http://cluster.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{healthy()},
clusterconditions: []toolchainv1alpha1.Condition{healthy()},
status: toolchainv1alpha1.ToolchainClusterStatus{},
},
"NotFoundNoCondition": {
tctype: "not-found",
apiendpoint: "http://not-found.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{offline()},
clusterconditions: []toolchainv1alpha1.Condition{offline()},
status: toolchainv1alpha1.ToolchainClusterStatus{},
},
//ToolchainCluster.status already contains conditions
"UnstableContainsCondition": {
tctype: "unstable",
apiendpoint: "http://unstable.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{unhealthy(), notOffline()},
clusterconditions: []toolchainv1alpha1.Condition{unhealthy(), notOffline()},
status: withStatus(healthy()),
},
"StableContainsCondition": {
tctype: "stable",
apiendpoint: "http://cluster.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{healthy()},
clusterconditions: []toolchainv1alpha1.Condition{healthy()},
status: withStatus(offline()),
},
"NotFoundContainsCondition": {
tctype: "not-found",
apiendpoint: "http://not-found.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{offline()},
clusterconditions: []toolchainv1alpha1.Condition{offline()},
status: withStatus(healthy()),
},
//if the connection cannot be established at beginning, then it should be offline
"OfflineConnectionNotEstablished": {
tctype: "failing",
apiendpoint: "http://failing.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{offline()},
clusterconditions: []toolchainv1alpha1.Condition{offline()},
status: toolchainv1alpha1.ToolchainClusterStatus{},
},
//if no zones nor region is retrieved, then keep the current
"NoZoneKeepCurrent": {
tctype: "stable",
apiendpoint: "http://cluster.com",
clusterconditions: []toolchainv1alpha1.ToolchainClusterCondition{healthy()},
clusterconditions: []toolchainv1alpha1.Condition{healthy()},
status: withStatus(offline()),
},
}
Expand Down Expand Up @@ -123,12 +123,12 @@ func TestClusterHealthChecks(t *testing.T) {
}
}

func withStatus(conditions ...toolchainv1alpha1.ToolchainClusterCondition) toolchainv1alpha1.ToolchainClusterStatus {
func withStatus(conditions ...toolchainv1alpha1.Condition) toolchainv1alpha1.ToolchainClusterStatus {
return toolchainv1alpha1.ToolchainClusterStatus{
Conditions: conditions,
}
}
func assertClusterStatus(t *testing.T, cl client.Client, clusterName string, clusterConds ...toolchainv1alpha1.ToolchainClusterCondition) {
func assertClusterStatus(t *testing.T, cl client.Client, clusterName string, clusterConds ...toolchainv1alpha1.Condition) {
tc := &toolchainv1alpha1.ToolchainCluster{}
err := cl.Get(context.TODO(), test.NamespacedName("test-namespace", clusterName), tc)
require.NoError(t, err)
Expand All @@ -146,30 +146,30 @@ ExpConditions:
assert.Failf(t, "condition not found", "the list of conditions %v doesn't contain the expected condition %v", tc.Status.Conditions, expCond)
}
}
func healthy() toolchainv1alpha1.ToolchainClusterCondition {
return toolchainv1alpha1.ToolchainClusterCondition{
Type: toolchainv1alpha1.ToolchainClusterReady,
func healthy() toolchainv1alpha1.Condition {
return toolchainv1alpha1.Condition{
Type: toolchainv1alpha1.ConditionReady,
Status: corev1.ConditionTrue,
Reason: "ClusterReady",
Message: "/healthz responded with ok",
}
}
func unhealthy() toolchainv1alpha1.ToolchainClusterCondition {
return toolchainv1alpha1.ToolchainClusterCondition{Type: toolchainv1alpha1.ToolchainClusterReady,
func unhealthy() toolchainv1alpha1.Condition {
return toolchainv1alpha1.Condition{Type: toolchainv1alpha1.ConditionReady,
Status: corev1.ConditionFalse,
Reason: "ClusterNotReady",
Message: "/healthz responded without ok",
}
}
func offline() toolchainv1alpha1.ToolchainClusterCondition {
return toolchainv1alpha1.ToolchainClusterCondition{Type: toolchainv1alpha1.ToolchainClusterOffline,
func offline() toolchainv1alpha1.Condition {
return toolchainv1alpha1.Condition{Type: toolchainv1alpha1.ToolchainClusterOffline,
Status: corev1.ConditionTrue,
Reason: "ClusterNotReachable",
Message: "cluster is not reachable",
}
}
func notOffline() toolchainv1alpha1.ToolchainClusterCondition {
return toolchainv1alpha1.ToolchainClusterCondition{Type: toolchainv1alpha1.ToolchainClusterOffline,
func notOffline() toolchainv1alpha1.Condition {
return toolchainv1alpha1.Condition{Type: toolchainv1alpha1.ToolchainClusterOffline,
Status: corev1.ConditionFalse,
Reason: "ClusterReachable",
Message: "cluster is reachable",
Expand Down
71 changes: 69 additions & 2 deletions controllers/toolchaincluster/toolchaincluster_controller.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package toolchaincluster

import (
"bytes"
"context"
"fmt"
"time"

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
"github.com/codeready-toolchain/toolchain-common/pkg/cluster"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
kubeclientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
Expand Down Expand Up @@ -54,13 +58,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
cachedCluster, ok := cluster.GetCachedToolchainCluster(toolchainCluster.Name)
if !ok {
err := fmt.Errorf("cluster %s not found in cache", toolchainCluster.Name)
toolchainCluster.Status.Conditions = []toolchainv1alpha1.ToolchainClusterCondition{clusterOfflineCondition()}
toolchainCluster.Status.Conditions = []toolchainv1alpha1.Condition{clusterOfflineCondition()}
if err := r.Client.Status().Update(ctx, toolchainCluster); err != nil {
reqLogger.Error(err, "failed to update the status of ToolchainCluster")
}
return reconcile.Result{}, err
}

if err = r.migrateSecretToKubeConfig(ctx, toolchainCluster); err != nil {
return reconcile.Result{}, err
}

clientSet, err := kubeclientset.NewForConfig(cachedCluster.RestConfig)
if err != nil {
reqLogger.Error(err, "cannot create ClientSet for the ToolchainCluster")
Expand All @@ -72,11 +80,70 @@ func (r *Reconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.
remoteClusterClientset: clientSet,
logger: reqLogger,
}
//update the status of the individual cluster.
// update the status of the individual cluster.
if err := healthChecker.updateIndividualClusterStatus(ctx, toolchainCluster); err != nil {
reqLogger.Error(err, "unable to update cluster status of ToolchainCluster")
return reconcile.Result{}, err
}

return reconcile.Result{RequeueAfter: r.RequeAfter}, nil
}

func (r *Reconciler) migrateSecretToKubeConfig(ctx context.Context, tc *toolchainv1alpha1.ToolchainCluster) error {
if len(tc.Spec.SecretRef.Name) == 0 {
return nil
}

secret := &corev1.Secret{}
if err := r.Client.Get(ctx, client.ObjectKey{Name: tc.Spec.SecretRef.Name, Namespace: tc.Namespace}, secret); err != nil {
return err
}

token := secret.Data["token"]
apiEndpoint := tc.Spec.APIEndpoint
operatorNamespace := tc.Labels["namespace"]
insecureTls := len(tc.Spec.DisabledTLSValidations) == 1 && tc.Spec.DisabledTLSValidations[0] == "*"
// we ignore the Spec.CABundle here because we don't want it migrated. The new configurations are free
// to use the certificate data for the connections but we don't want to migrate the existing certificates.
kubeConfig := composeKubeConfigFromData(token, apiEndpoint, operatorNamespace, insecureTls)

data, err := clientcmd.Write(kubeConfig)
if err != nil {
return err
}

origKubeConfigData := secret.Data["kubeconfig"]
secret.Data["kubeconfig"] = data

if !bytes.Equal(origKubeConfigData, data) {
if err = r.Client.Update(ctx, secret); err != nil {
return err
}
}

return nil
}

func composeKubeConfigFromData(token []byte, apiEndpoint, operatorNamespace string, insecureTls bool) clientcmdapi.Config {
return clientcmdapi.Config{
Contexts: map[string]*clientcmdapi.Context{
"ctx": {
Cluster: "cluster",
Namespace: operatorNamespace,
AuthInfo: "auth",
},
},
CurrentContext: "ctx",
Clusters: map[string]*clientcmdapi.Cluster{
"cluster": {
Server: apiEndpoint,
InsecureSkipTLSVerify: insecureTls,
},
},
AuthInfos: map[string]*clientcmdapi.AuthInfo{
"auth": {
Token: string(token),
},
},
}
}
Loading

0 comments on commit 6e615a7

Please sign in to comment.