这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions deploy/crds/core.humio.com_humioclusters_crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ kind: CustomResourceDefinition
metadata:
name: humioclusters.core.humio.com
spec:
additionalPrinterColumns:
- JSONPath: .status.clusterState
description: The state of the cluster
name: State
type: string
- JSONPath: .status.clusterNodeCount
description: The number of nodes in the cluster
name: Nodes
type: string
- JSONPath: .status.clusterVersion
description: The version of humior
name: Version
type: string
group: core.humio.com
names:
kind: HumioCluster
Expand Down Expand Up @@ -151,10 +164,15 @@ spec:
allDataAvailable:
description: Current state set by operator.
type: string
clusterNodeCount:
description: ClusterNodeCount is the number of nodes of humio running
type: integer
clusterState:
description: 'ClusterState will be empty before the cluster is bootstrapped.
From there it can be "Bootstrapping" or "Operational" TODO: other
states?'
From there it can be "Bootstrapping" or "Running" TODO: other states?'
type: string
clusterVersion:
description: ClusterVersion is the version of humio running
type: string
stateLastUpdated:
format: int64
Expand Down
16 changes: 15 additions & 1 deletion pkg/apis/core/v1alpha1/humiocluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
// HumioClusterStateBoostrapping is the Bootstrapping state of the cluster
HumioClusterStateBoostrapping = "Bootstrapping"
// HumioClusterStateRunning is the Running state of the cluster
HumioClusterStateRunning = "Running"
)

// HumioClusterSpec defines the desired state of HumioCluster
type HumioClusterSpec struct {
// Desired container image including the image tag
Expand All @@ -26,16 +33,23 @@ type HumioClusterStatus struct {
StateLastUpdatedUnix int64 `json:"stateLastUpdated,omitempty"`
// Current state set by operator.
AllDataAvailable string `json:"allDataAvailable,omitempty"`
// ClusterState will be empty before the cluster is bootstrapped. From there it can be "Bootstrapping" or "Operational"
// ClusterState will be empty before the cluster is bootstrapped. From there it can be "Bootstrapping" or "Running"
// TODO: other states?
ClusterState string `json:"clusterState,omitempty"`
// ClusterVersion is the version of humio running
ClusterVersion string `json:"clusterVersion,omitempty"`
// ClusterNodeCount is the number of nodes of humio running
ClusterNodeCount int `json:"clusterNodeCount,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// HumioCluster is the Schema for the humioclusters API
// +kubebuilder:subresource:status
// +kubebuilder:resource:path=humioclusters,scope=Namespaced
// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.clusterState",description="The state of the cluster"
// +kubebuilder:printcolumn:name="Nodes",type="string",JSONPath=".status.clusterNodeCount",description="The number of nodes in the cluster"
// +kubebuilder:printcolumn:name="Version",type="string",JSONPath=".status.clusterVersion",description="The version of humior"
type HumioCluster struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Expand Down
77 changes: 69 additions & 8 deletions pkg/controller/humiocluster/humiocluster_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (r *ReconcileHumioCluster) Reconcile(request reconcile.Request) (reconcile.
// Assume we are bootstrapping if no cluster state is set.
// TODO: this is a workaround for the issue where humio pods cannot start up at the same time during the first boot
if humioCluster.Status.ClusterState == "" {
r.setClusterStatus(context.TODO(), "Boostrapping", humioCluster)
r.setClusterState(context.TODO(), corev1alpha1.HumioClusterStateBoostrapping, humioCluster)
}

// Ensure developer password is a k8s secret
Expand All @@ -149,13 +149,34 @@ func (r *ReconcileHumioCluster) Reconcile(request reconcile.Request) (reconcile.
}

// Ensure pods exist. Will requeue if not all pods are created and ready
if humioCluster.Status.ClusterState == corev1alpha1.HumioClusterStateBoostrapping {
result, err = r.ensurePodsBootstrapped(context.TODO(), humioCluster)
if result != emptyResult || err != nil {
return result, err
}
}

r.setClusterState(context.TODO(), corev1alpha1.HumioClusterStateRunning, humioCluster)

defer func(context context.Context, humioCluster *corev1alpha1.HumioCluster) {
pods, _ := ListPods(r.client, humioCluster)
r.setClusterNodeCount(context, len(pods), humioCluster)
}(context.TODO(), humioCluster)

// TODO: get cluster version from humio api
defer func(context context.Context, humioClient humio.Client, humioCluster *corev1alpha1.HumioCluster) {
status, err := humioClient.Status()
if err != nil {
r.logger.Info("unable to get status: %s", err)
}
r.setClusterVersion(context, status.Version, humioCluster)
}(context.TODO(), r.humioClient, humioCluster)

result, err = r.ensurePodsExist(context.TODO(), humioCluster)
if result != emptyResult || err != nil {
return result, err
}

r.setClusterStatus(context.TODO(), "Running", humioCluster)

// Ensure service exists
err = r.ensureServiceExists(context.TODO(), humioCluster)
if err != nil {
Expand All @@ -173,6 +194,7 @@ func (r *ReconcileHumioCluster) Reconcile(request reconcile.Request) (reconcile.
return reconcile.Result{}, err
}

// TODO: wait until all pods are ready before continuing
clusterController := humio.NewClusterController(r.humioClient)
err = r.ensurePartitionsAreBalanced(*clusterController, humioCluster)
if err != nil {
Expand All @@ -183,11 +205,21 @@ func (r *ReconcileHumioCluster) Reconcile(request reconcile.Request) (reconcile.
return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 30}, nil
}

// setClusterStatus is used to change the cluster status
// setClusterState is used to change the cluster state
// TODO: we use this to determine if we should have a delay between startup of humio pods during bootstrap vs starting up pods during an image update
func (r *ReconcileHumioCluster) setClusterStatus(context context.Context, clusterState string, humioCluster *corev1alpha1.HumioCluster) error {
func (r *ReconcileHumioCluster) setClusterState(context context.Context, clusterState string, humioCluster *corev1alpha1.HumioCluster) error {
humioCluster.Status.ClusterState = clusterState
return r.client.Update(context, humioCluster)
return r.client.Status().Update(context, humioCluster)
}

func (r *ReconcileHumioCluster) setClusterVersion(context context.Context, clusterVersion string, humioCluster *corev1alpha1.HumioCluster) error {
humioCluster.Status.ClusterVersion = clusterVersion
return r.client.Status().Update(context, humioCluster)
}

func (r *ReconcileHumioCluster) setClusterNodeCount(context context.Context, clusterNodeCount int, humioCluster *corev1alpha1.HumioCluster) error {
humioCluster.Status.ClusterNodeCount = clusterNodeCount
return r.client.Status().Update(context, humioCluster)
}

func (r *ReconcileHumioCluster) ensurePodLabels(context context.Context, hc *corev1alpha1.HumioCluster) error {
Expand Down Expand Up @@ -315,7 +347,7 @@ func (r *ReconcileHumioCluster) ensureMismatchedPodVersionsAreDeleted(conetext c

// TODO: change to create 1 pod at a time, return Requeue=true and RequeueAfter.
// check that other pods, if they exist, are in a ready state
func (r *ReconcileHumioCluster) ensurePodsExist(conetext context.Context, humioCluster *corev1alpha1.HumioCluster) (reconcile.Result, error) {
func (r *ReconcileHumioCluster) ensurePodsBootstrapped(conetext context.Context, humioCluster *corev1alpha1.HumioCluster) (reconcile.Result, error) {
// Ensure we have pods for the defined NodeCount.
// If scaling down, we will handle the extra/obsolete pods later.
foundPodList, err := ListPods(r.client, humioCluster)
Expand All @@ -341,7 +373,7 @@ func (r *ReconcileHumioCluster) ensurePodsExist(conetext context.Context, humioC
return reconcile.Result{}, nil
}

if podsNotReadyCount > 0 && humioCluster.Status.ClusterState == "Bootstrapping" {
if podsNotReadyCount > 0 {
r.logger.Info(fmt.Sprintf("there are %d humio pods that are not ready. all humio pods must report ready before reconciliation can continue", podsNotReadyCount))
return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, nil
}
Expand All @@ -367,6 +399,35 @@ func (r *ReconcileHumioCluster) ensurePodsExist(conetext context.Context, humioC
return reconcile.Result{}, nil
}

func (r *ReconcileHumioCluster) ensurePodsExist(conetext context.Context, humioCluster *corev1alpha1.HumioCluster) (reconcile.Result, error) {
// Ensure we have pods for the defined NodeCount.
// If scaling down, we will handle the extra/obsolete pods later.
foundPodList, err := ListPods(r.client, humioCluster)
if err != nil {
return reconcile.Result{}, fmt.Errorf("failed to list pods: %s", err)
}

if len(foundPodList) < humioCluster.Spec.NodeCount {
pod, err := r.constructPod(humioCluster)
if err != nil {
return reconcile.Result{}, fmt.Errorf("unable to construct pod for HumioCluster: %v", err)
}

err = r.client.Create(context.TODO(), pod)
if err != nil {
log.Info(fmt.Sprintf("unable to create pod: %v", err))
return reconcile.Result{Requeue: true, RequeueAfter: time.Second * 5}, fmt.Errorf("unable to create Pod for HumioCluster: %v", err)
}
log.Info(fmt.Sprintf("successfully created pod %s for HumioCluster %s", pod.Name, humioCluster.Name))
metricPodsCreated.Inc()
// We have created a pod. Requeue immediately even if the pod is not ready. We will check the readiness status on the next reconciliation.
return reconcile.Result{Requeue: true}, nil
}

// TODO: what should happen if we have more pods than are expected?
return reconcile.Result{}, nil
}

// TODO: extend this (or create separate method) to take this password and perform a login, get the jwt token and then call the api to get the persistent api token and also store that as a secret
// this functionality should perhaps go into humio.cluster_auth.go
func (r *ReconcileHumioCluster) ensureDeveloperUserPasswordExists(conetext context.Context, humioCluster *corev1alpha1.HumioCluster) error {
Expand Down
Loading