-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Due to CRDs changes the reconcile must be updated
- Loading branch information
Showing
2 changed files
with
87 additions
and
68 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 |
---|---|---|
|
@@ -16,17 +16,15 @@ limitations under the License. | |
|
||
package controllers | ||
|
||
//TODO mshitrit make sure fence agents and other necessary executables are installed in the pod | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/go-logr/logr" | ||
|
||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
apiErrors "k8s.io/apimachinery/pkg/api/errors" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
|
@@ -37,11 +35,6 @@ import ( | |
"github.com/medik8s/fence-agents-remediation/pkg/cli" | ||
) | ||
|
||
const ( | ||
//TODO mshitrit verify that template is created with this name | ||
fenceAgentsTemplateName = "fenceagentsremediationtemplate-default" | ||
) | ||
|
||
var ( | ||
faPodLabels = map[string]string{"app": "fence-agents-remediation-operator"} | ||
) | ||
|
@@ -53,6 +46,13 @@ type FenceAgentsRemediationReconciler struct { | |
Scheme *runtime.Scheme | ||
} | ||
|
||
// SetupWithManager sets up the controller with the Manager. | ||
func (r *FenceAgentsRemediationReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&v1alpha1.FenceAgentsRemediation{}). | ||
Complete(r) | ||
} | ||
|
||
//+kubebuilder:rbac:groups=core,resources=pods/exec,verbs=create | ||
//+kubebuilder:rbac:groups=core,resources=pods,verbs=get;list;watch;update;delete;deletecollection | ||
//+kubebuilder:rbac:groups=fence-agents-remediation.medik8s.io,resources=fenceagentsremediations,verbs=get;list;watch;create;update;patch;delete | ||
|
@@ -69,69 +69,54 @@ type FenceAgentsRemediationReconciler struct { | |
// For more details, check Reconcile and its Result here: | ||
// - https://pkg.go.dev/sigs.k8s.io/[email protected]/pkg/reconcile | ||
func (r *FenceAgentsRemediationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
r.Log.Info("started reconcile") | ||
defer r.Log.Info("finished reconcile") | ||
r.Log.Info("Begin FenceAgentsRemediation Reconcile") | ||
defer r.Log.Info("Finish FenceAgentsRemediation Reconcile") | ||
emptyResult := ctrl.Result{} | ||
|
||
// Fetch the FenceAgentsRemediation instance | ||
far := &v1alpha1.FenceAgentsRemediation{} | ||
if err := r.Get(ctx, req.NamespacedName, far); err != nil { | ||
if apiErrors.IsNotFound(err) { | ||
// FAR is deleted, stop reconciling | ||
r.Log.Info("Fence Agents Remediation not found, nothing to do") | ||
return ctrl.Result{}, nil | ||
r.Log.Info("FAR CR is deleted - nothing to do", "CR Name", req.Name, "CR Namespace", req.Namespace) | ||
return emptyResult, nil | ||
} | ||
r.Log.Error(err, "failed to get FAR") | ||
return ctrl.Result{}, err | ||
r.Log.Error(err, "failed to get FAR CR") | ||
return emptyResult, err | ||
} | ||
key := client.ObjectKey{Namespace: req.Namespace, Name: fenceAgentsTemplateName} | ||
farTemplate := &v1alpha1.FenceAgentsRemediationTemplate{} | ||
if err := r.Get(ctx, key, farTemplate); err != nil { | ||
r.Log.Error(err, "failed to get FAR template") | ||
return ctrl.Result{}, err | ||
} | ||
|
||
pod, err := r.getFAPod(req.NamespacedName.Namespace) | ||
// TODO: Validate FAR CR name to nodeName. Run isNodeNameValid | ||
// Fetch the FAR's pod | ||
r.Log.Info("Fetch FAR's pod") | ||
pod, err := r.getFenceAgentsPod(req.Namespace) | ||
if err != nil { | ||
return ctrl.Result{}, err | ||
return emptyResult, err | ||
} | ||
|
||
// Build CLI executer for FAR's pod | ||
r.Log.Info("Build CLI executer for FAR's pod") | ||
ex, err := cli.NewExecuter(pod) | ||
if err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
|
||
faParams := buildFenceAgentParams(farTemplate, far) | ||
cmd := append([]string{farTemplate.Spec.Agent}, faParams...) | ||
//fence_ipmilan --ip=192.168.111.1 --ipport=6233 --username=admin --password=password --action=status --lanplus --verbose | ||
if _, _, err := ex.Execute(cmd); err != nil { | ||
return ctrl.Result{}, err | ||
return emptyResult, err | ||
} | ||
|
||
return ctrl.Result{}, nil | ||
} | ||
|
||
func buildFenceAgentParams(farTemplate *v1alpha1.FenceAgentsRemediationTemplate, far *v1alpha1.FenceAgentsRemediation) []string { | ||
var fenceAgentParams []string | ||
for paramName, paramVal := range farTemplate.Spec.SharedParameters { | ||
fenceAgentParams = appendParamToSlice(fenceAgentParams, string(paramName), paramVal) | ||
|
||
//TODO: Check that FA is excutable? run cli.IsExecuteable | ||
r.Log.Info("Create and execute the fence agent", "Fence Agent", far.Spec.Agent) | ||
faParams, err := buildFenceAgentParams(far) | ||
if err != nil { | ||
return emptyResult, err | ||
} | ||
|
||
nodeName := v1alpha1.NodeName(far.Name) | ||
for paramName, nodeMap := range farTemplate.Spec.NodeParameters { | ||
fenceAgentParams = appendParamToSlice(fenceAgentParams, string(paramName), nodeMap[nodeName]) | ||
cmd := append([]string{far.Spec.Agent}, faParams...) | ||
// The Fence Agent is excutable and the parameters are valid but we don't know about their values | ||
if _, _, err := ex.Execute(cmd); err != nil { | ||
//TODO: better seperation between errors from wrong shared parameters values and wrong node parameters values | ||
return emptyResult, err | ||
} | ||
|
||
return fenceAgentParams | ||
} | ||
|
||
// SetupWithManager sets up the controller with the Manager. | ||
func (r *FenceAgentsRemediationReconciler) SetupWithManager(mgr ctrl.Manager) error { | ||
return ctrl.NewControllerManagedBy(mgr). | ||
For(&v1alpha1.FenceAgentsRemediation{}). | ||
Complete(r) | ||
return emptyResult, nil | ||
} | ||
|
||
func (r *FenceAgentsRemediationReconciler) getFAPod(namespace string) (*corev1.Pod, error) { | ||
// getFenceAgentsPod fetches the FAR pod based on FAR's label and namespace | ||
func (r *FenceAgentsRemediationReconciler) getFenceAgentsPod(namespace string) (*corev1.Pod, error) { | ||
|
||
pods := new(corev1.PodList) | ||
|
||
|
@@ -143,11 +128,12 @@ func (r *FenceAgentsRemediationReconciler) getFAPod(namespace string) (*corev1.P | |
} | ||
if err := r.Client.List(context.Background(), pods, &options); err != nil { | ||
r.Log.Error(err, "failed fetching Fence Agent layer pod") | ||
// err := errors.New("failed fetching Fence Agent layer pod") | ||
return nil, err | ||
} | ||
if len(pods.Items) == 0 { | ||
r.Log.Info("No Fence Agent pods were found") | ||
podNotFoundErr := &errors.StatusError{ErrStatus: metav1.Status{ | ||
podNotFoundErr := &apiErrors.StatusError{ErrStatus: metav1.Status{ | ||
Status: metav1.StatusFailure, | ||
Code: http.StatusNotFound, | ||
Reason: metav1.StatusReasonNotFound, | ||
|
@@ -158,11 +144,33 @@ func (r *FenceAgentsRemediationReconciler) getFAPod(namespace string) (*corev1.P | |
|
||
} | ||
|
||
func appendParamToSlice(fenceAgentParams []string, paramName string, paramVal string) []string { | ||
// buildFenceAgentParams collects the FAR's parameters for the node based on FAR CR | ||
func buildFenceAgentParams(far *v1alpha1.FenceAgentsRemediation) ([]string, error) { | ||
var fenceAgentParams []string | ||
for paramName, paramVal := range far.Spec.SharedParameters { | ||
fenceAgentParams = appendParamToSlice(fenceAgentParams, paramName, paramVal) | ||
} | ||
|
||
nodeName := v1alpha1.NodeName(far.Name) | ||
for paramName, nodeMap := range far.Spec.NodeParameters { | ||
if nodeVal, isFound := nodeMap[nodeName]; isFound { | ||
fenceAgentParams = appendParamToSlice(fenceAgentParams, paramName, nodeVal) | ||
} else { | ||
err := errors.New("node parameter is required, and cannot be empty") | ||
return nil, err | ||
} | ||
} | ||
return fenceAgentParams, nil | ||
} | ||
|
||
// appendParamToSlice appends parameters in a key-value manner, when value can be empty | ||
func appendParamToSlice(fenceAgentParams []string, paramName v1alpha1.ParameterName, paramVal string) []string { | ||
if paramVal != "" { | ||
fenceAgentParams = append(fenceAgentParams, fmt.Sprintf("%s=%s", paramName, paramVal)) | ||
} else { | ||
fenceAgentParams = append(fenceAgentParams, paramName) | ||
fenceAgentParams = append(fenceAgentParams, string(paramName)) | ||
} | ||
return fenceAgentParams | ||
} | ||
|
||
// TODO: Add isNodeNameValid function which call listNodeNames to validate the FAR's name with the cluster node names |
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