Skip to content

Commit

Permalink
cnf ran: ztp hub templating and node delete migration
Browse files Browse the repository at this point in the history
  • Loading branch information
klaskosk committed Jul 11, 2024
1 parent 09c09b6 commit 2c21521
Show file tree
Hide file tree
Showing 6 changed files with 589 additions and 3 deletions.
24 changes: 24 additions & 0 deletions tests/cnf/ran/ztp/internal/helper/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@ func WaitForPolicyToExist(
return policy, err
}

// WaitForPolicyMessageToContainSubstring waits for the policy status message to contain the specified substring.
func WaitForPolicyMessageToContainSubstring(client *clients.Settings, name, namespace, subString string) error {
glog.V(tsparams.LogLevel).Infof("Checking policy '%s' in namespace '%s' for message substring", name, namespace)

return wait.PollUntilContextTimeout(context.TODO(),
tsparams.ArgoCdChangeInterval, tsparams.ArgoCdChangeTimeout, true, func(ctx context.Context) (bool, error) {
policy, err := ocm.PullPolicy(client, name, namespace)
if err != nil {
return false, err
}

details := policy.Definition.Status.Details
if len(details) > 0 && len(details[0].History) > 0 {
message := details[0].History[0].Message

glog.V(tsparams.LogLevel).Infof("Checking if message '%s' contains substring '%s'", message, subString)

return strings.Contains(message, subString), nil
}

return false, nil
})
}

// WaitUntilSearchCollectorEnabled waits up to timeout until the KAC has the search collector addon enabled.
func WaitUntilSearchCollectorEnabled(kac *ocm.KACBuilder, timeout time.Duration) error {
glog.V(tsparams.LogLevel).Infof(
Expand Down
182 changes: 182 additions & 0 deletions tests/cnf/ran/ztp/internal/helper/nodedelete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package helper

import (
"context"
"fmt"
"time"

"github.com/golang/glog"
"github.com/openshift-kni/eco-goinfra/pkg/assisted"
"github.com/openshift-kni/eco-goinfra/pkg/bmh"
"github.com/openshift-kni/eco-goinfra/pkg/clients"
"github.com/openshift-kni/eco-goinfra/pkg/nodes"
. "github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/raninittools"
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/ztp/internal/tsparams"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
)

// IsSnoPlusOne checks if the specified cluster has one master and one worker node.
func IsSnoPlusOne(client *clients.Settings) (bool, error) {
masters, err := listNodesByRole(client, "master")
if err != nil {
return false, err
}

if len(masters) != 1 {
return false, nil
}

glog.V(tsparams.LogLevel).Info("Exactly one master node found")

workers, err := listNodesByRole(client, "worker")
if err != nil {
return false, err
}

trueWorkers := 0

for _, worker := range workers {
if isNodeMaster(worker) {
trueWorkers++
}
}

if trueWorkers != 1 {
return false, nil
}

glog.V(tsparams.LogLevel).Info("Exactly one worker node found")

return true, nil
}

// GetPlusOneWorkerName gets the name of the one worker in a SNO+1 cluster.
func GetPlusOneWorkerName(client *clients.Settings) (string, error) {
workers, err := listNodesByRole(client, "worker")
if err != nil {
return "", err
}

for _, worker := range workers {
if !isNodeMaster(worker) {
return worker.Definition.Name, nil
}
}

return "", fmt.Errorf("could not find a worker node for cluster")
}

// IsClusterStable checks if the provided cluster does not have any unschedulable nodes.
func IsClusterStable(client *clients.Settings) (bool, error) {
nodeList, err := nodes.List(client)
if err != nil {
return false, err
}

for _, node := range nodeList {
if node.Definition.Spec.Unschedulable {
return false, nil
}
}

return true, nil
}

// WaitForNumberOfNodes waits up to timeout until the number of nodes on the cluster matches the expected.
func WaitForNumberOfNodes(client *clients.Settings, expected int, timeout time.Duration) error {
return wait.PollUntilContextTimeout(
context.TODO(), 5*time.Second, timeout, true, func(ctx context.Context) (bool, error) {
nodeList, err := nodes.List(client)
if err != nil {
return false, err
}

if len(nodeList) == expected {
return true, nil
}

glog.V(tsparams.LogLevel).Infof("Expected %d nodes but found %d nodes", expected, len(nodeList))

return false, nil
})
}

// GetBmhNamespace returns the namespace for the specified BareMetalHost, if it exists.
func GetBmhNamespace(client *clients.Settings, bmhName string) (string, error) {
bmhList, err := bmh.ListInAllNamespaces(client)
if err != nil {
return "", err
}

for _, bmhBuilder := range bmhList {
if bmhBuilder.Definition.Name == bmhName {
return bmhBuilder.Definition.Namespace, nil
}
}

return "", fmt.Errorf("BareMetalHost %s not found", bmhName)
}

// WaitForBMHDeprovisioning waits up to the specified timeout till the BMH and agent with the provided name and
// namespace are no longer found.
func WaitForBMHDeprovisioning(client *clients.Settings, name, namespace string, timeout time.Duration) error {
return wait.PollUntilContextTimeout(
context.TODO(), tsparams.ArgoCdChangeInterval, timeout, true, func(ctx context.Context) (bool, error) {
glog.V(tsparams.LogLevel).Infof("Checking if BareMetalHost %s in namespace %s is deprovisioned", name, namespace)

_, err := bmh.Pull(client, name, namespace)
if err == nil {
return false, nil
}

_, err = assisted.PullAgent(client, name, namespace)
if err == nil {
return false, nil
}

return true, nil
})
}

// WaitForBMHAnnotation waits up to timeout until the specified annotation is present on the BMH.
func WaitForBMHAnnotation(bareMetalHost *bmh.BmhBuilder, annotation string, timeout time.Duration) error {
return wait.PollUntilContextTimeout(
context.TODO(), tsparams.ArgoCdChangeInterval, timeout, true, func(ctx context.Context) (bool, error) {
if !bareMetalHost.Exists() {
glog.V(tsparams.LogLevel).Infof("BMH %s in namespace %s does not exist")

return false, fmt.Errorf(
"bmh object %s does not exist in namespace %s", bareMetalHost.Definition.Name, bareMetalHost.Definition.Namespace)
}

if _, ok := bareMetalHost.Object.Annotations[annotation]; !ok {
return false, nil
}

glog.V(tsparams.LogLevel).Infof(
"Annotation %s found for BMH %s/%s", annotation, bareMetalHost.Definition.Name, bareMetalHost.Definition.Namespace)

return true, nil
})
}

// listNodesByRole returns a list of nodes that have the specified role.
func listNodesByRole(client *clients.Settings, role string) ([]*nodes.Builder, error) {
return nodes.List(client, metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s/%s=", RANConfig.KubernetesRolePrefix, role),
})
}

// isNodeMaster checks whether the provided node is a master, i.e. it is not a master or control plane node.
func isNodeMaster(node *nodes.Builder) bool {
masterLabels := []string{"node-role.kubernetes.io/master", RANConfig.ControlPlaneLabel}

for _, label := range masterLabels {
if _, exists := node.Definition.Labels[label]; exists {
return true
}
}

return false
}
34 changes: 31 additions & 3 deletions tests/cnf/ran/ztp/internal/tsparams/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,17 @@ const (
LabelArgoCdAcmCrsTestCases = "ztp-argocd-acm-crs"
// LabelArgoCdClustersAppTestCases is the label for the Argo CD clusters app test cases.
LabelArgoCdClustersAppTestCases = "ztp-argocd-clusters"

// TestNamespace is the namespace used for ZTP tests.
TestNamespace = "ztp-test"
// LabelArgoCdHubTemplatingTestCases is the label for a particular set of test cases.
LabelArgoCdHubTemplatingTestCases = "ztp-argocd-hub-templating"
// LabelArgoCdNodeDeletionTestCases is the label for a particular set of test cases.
LabelArgoCdNodeDeletionTestCases = "ztp-argocd-node-delete"

// MultiClusterHubOperator is the name of the multi cluster hub operator.
MultiClusterHubOperator = "multiclusterhub-operator"
// AcmPolicyGeneratorName is the name of the ACM policy generator container.
AcmPolicyGeneratorName = "acm-policy-generator"
// TalmHubPodName is the name of the TALM pod on the hub cluster.
TalmHubPodName = "cluster-group-upgrades-controller-manager"

// ArgoCdPoliciesAppName is the name of the policies app in Argo CD.
ArgoCdPoliciesAppName = "policies"
Expand All @@ -38,11 +41,36 @@ const (
ZtpTestPathClustersApp = "ztp-test/klusterlet-addon"
// ZtpTestPathRemoveNmState is the git path for the remove nm state test.
ZtpTestPathRemoveNmState = "ztp-test/remove-nmstate"
// ZtpTestPathTemplatingPrintf is the git path for the templating printf test.
ZtpTestPathTemplatingPrintf = "ztp-test/hub-templating-printf"
// ZtpTestPathTemplatingFromSecret is the git path for the templating from secret test.
ZtpTestPathTemplatingFromSecret = "ztp-test/hub-templating-fromsecret"
// ZtpTestPathTemplatingAutoIndent is the git path for the templating auto indent test.
ZtpTestPathTemplatingAutoIndent = "ztp-test/hub-templating-autoindent"
// ZtpTestPathTemplatingLookupInvalid is the git path for the templating lookup invalid test.
ZtpTestPathTemplatingLookupInvalid = "ztp-test/hub-templating-lookup-invalid"
// ZtpTestPathTemplatingValid is the git path for the templating valid test.
ZtpTestPathTemplatingValid = "ztp-test/hub-templating-valid"
// ZtpTestPathNodeDeleteAddAnnotation is the git path for the node deletion add annotation test.
ZtpTestPathNodeDeleteAddAnnotation = "ztp-test/node-delete/add-annotation"
// ZtpTestPathNodeDeleteAddSuppression is the git path for the node deletion add suppression test.
ZtpTestPathNodeDeleteAddSuppression = "ztp-test/node-delete/add-suppression"
// ZtpKustomizationPath is the path to the kustomization file in the ztp test.
ZtpKustomizationPath = "/kustomization.yaml"

// TestNamespace is the namespace used for ZTP tests.
TestNamespace = "ztp-test"
// AcmCrsPolicyName is the name of the policy for ACM CRs.
AcmCrsPolicyName = "acm-crs-policy"
// HubTemplatingPolicyName is the name used for the hub templating policy.
HubTemplatingPolicyName = "hub-templating-policy-sriov-config"
// HubTemplatingCguName is the name used for the hub templating CGU.
HubTemplatingCguName = "hub-templating"
// HubTemplatingCguNamespace is the namespace used by the hub templating CGU. It should be different than the
// policy namespace.
HubTemplatingCguNamespace = "default"
// NodeDeletionCrAnnotation is the annotation applied in the node deletion tests.
NodeDeletionCrAnnotation = "bmac.agent-install.openshift.io/remove-agent-and-node-on-delete"

// LogLevel is the verbosity of glog statements in this test suite.
LogLevel glog.Level = 90
Expand Down
9 changes: 9 additions & 0 deletions tests/cnf/ran/ztp/internal/tsparams/ztpvars.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/ranparam"
"github.com/openshift-kni/k8sreporter"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ArgoCdGitDetails is the details for a single app in ArgoCD.
Expand Down Expand Up @@ -33,4 +34,12 @@ var (
}
// ArgoCdAppDetails contains more details for each of the ArgoCdApps.
ArgoCdAppDetails = map[string]ArgoCdGitDetails{}

// InvalidManagedPoliciesCondition is the CGU condition for where there are invalid managed policies.
InvalidManagedPoliciesCondition = metav1.Condition{
Type: "Validated",
Status: metav1.ConditionFalse,
Reason: "NotAllManagedPoliciesExist",
Message: "Invalid managed policies",
}
)
Loading

0 comments on commit 2c21521

Please sign in to comment.