Skip to content

Commit

Permalink
cnf ran: ztp test migration preliminaries
Browse files Browse the repository at this point in the history
This is the first PR for migrating the ZTP test suite and includes the ztp directory with the helper and tsparams packages. Additionally, some helpers and parameters are moved from the TALM suite into the ran directory so they may be shared with the ZTP tests.
  • Loading branch information
klaskosk committed Jul 3, 2024
1 parent 971a878 commit ae26fd1
Show file tree
Hide file tree
Showing 33 changed files with 1,568 additions and 500 deletions.
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ linters-settings:
- github.com/onsi/ginkgo/v2
- github.com/openshift-kni/eco-gotests/tests/internal/inittools
- github.com/openshift-kni/eco-gotests/tests/cnf/core/network/internal/netinittools
- github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/raninittools
- github.com/openshift-kni/eco-gotests/tests/assisted/ztp/internal/ztpinittools
- github.com/openshift-kni/eco-gotests/tests/system-tests/ipsec/internal/ipsecinittools
- github.com/openshift-kni/eco-gotests/tests/system-tests/ran-du/internal/randuinittools
Expand Down
8 changes: 4 additions & 4 deletions tests/cnf/ran/containernshide/tests/containernshide.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ import (
"github.com/openshift-kni/eco-goinfra/pkg/reportxml"
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/containernshide/internal/tsparams"
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/cluster"
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/raninittools"
. "github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/raninittools"
)

var _ = Describe("Container Namespace Hiding", Label(tsparams.LabelContainerNSHideTestCases), func() {
It("should not have kubelet and crio using the same inode as systemd", reportxml.ID("53681"), func() {
By("Getting systemd inodes on cluster nodes")
systemdInodes, err := cluster.ExecCmdWithStdout(raninittools.Spoke1APIClient, 3, "readlink /proc/1/ns/mnt")
systemdInodes, err := cluster.ExecCmdWithStdout(Spoke1APIClient, 3, "readlink /proc/1/ns/mnt")
Expect(err).ToNot(HaveOccurred(), "Failed to check systemd inodes")

By("Getting kubelet inodes on cluster nodes")
kubeletInodes, err := cluster.ExecCmdWithStdout(
raninittools.Spoke1APIClient, 3, "readlink /proc/$(pidof kubelet)/ns/mnt")
Spoke1APIClient, 3, "readlink /proc/$(pidof kubelet)/ns/mnt")
Expect(err).ToNot(HaveOccurred(), "Failed to check kubelet inodes")

By("Getting crio inodes on cluster nodes")
crioInodes, err := cluster.ExecCmdWithStdout(raninittools.Spoke1APIClient, 3, "readlink /proc/$(pidof crio)/ns/mnt")
crioInodes, err := cluster.ExecCmdWithStdout(Spoke1APIClient, 3, "readlink /proc/$(pidof crio)/ns/mnt")
Expect(err).ToNot(HaveOccurred(), "Failed to check crio inodes")

Expect(len(systemdInodes)).To(Equal(len(kubeletInodes)),
Expand Down
15 changes: 15 additions & 0 deletions tests/cnf/ran/internal/cluster/cluster.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package cluster

import (
"context"
"fmt"
"os/exec"
"strings"
"time"

Expand All @@ -12,6 +14,19 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ExecLocalCommand runs the provided command with the provided args locally, cancelling execution if it exceeds
// timeout.
func ExecLocalCommand(timeout time.Duration, command string, args ...string) (string, error) {
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()

glog.V(ranparam.LogLevel).Infof("Locally executing command '%s' with args '%v'", command, args)

output, err := exec.CommandContext(ctx, command, args...).Output()

return string(output), err
}

// ExecCmd executes a command on the provided client on each node matching nodeSelector, retrying on internal errors
// retries times with a 10 second delay between retries, and ignores the stdout.
func ExecCmd(client *clients.Settings, retries uint, nodeSelector, command string) error {
Expand Down
203 changes: 187 additions & 16 deletions tests/cnf/ran/internal/ranconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@ import (
"os"
"path/filepath"
"runtime"
"time"

"github.com/golang/glog"
"github.com/kelseyhightower/envconfig"
"github.com/openshift-kni/eco-goinfra/pkg/bmc"
"github.com/openshift-kni/eco-goinfra/pkg/clients"
"github.com/openshift-kni/eco-gotests/tests/cnf/internal/cnfconfig"
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/ranhelper"
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/ranparam"
"github.com/openshift-kni/eco-gotests/tests/internal/inittools"
"gopkg.in/yaml.v2"
)

Expand All @@ -20,20 +25,48 @@ const (
// RANConfig contains configuration for the RAN directory.
type RANConfig struct {
*cnfconfig.CNFConfig
*HubConfig
*Spoke1Config
*Spoke2Config

MetricSamplingInterval string `yaml:"metricSamplingInterval" envconfig:"ECO_CNF_RAN_METRIC_SAMPLING_INTERVAL"`
NoWorkloadDuration string `yaml:"noWorkloadDuration" envconfig:"ECO_CNF_RAN_NO_WORKLOAD_DURATION"`
WorkloadDuration string `yaml:"workloadDuration" envconfig:"ECO_CNF_RAN_WORKLOAD_DURATION"`
StressngTestImage string `yaml:"stressngTestImage" envconfig:"ECO_CNF_RAN_STRESSNG_TEST_IMAGE"`
CnfTestImage string `yaml:"cnfTestImage" envconfig:"ECO_CNF_RAN_TEST_IMAGE"`
HubKubeconfig string `envconfig:"ECO_CNF_RAN_KUBECONFIG_HUB"`
Spoke2Kubeconfig string `envconfig:"ECO_CNF_RAN_KUBECONFIG_SPOKE2"`
BmcUsername string `yaml:"bmcUsername" envconfig:"ECO_CNF_RAN_BMC_USERNAME"`
BmcPassword string `yaml:"bmcPassword" envconfig:"ECO_CNF_RAN_BMC_PASSWORD"`
BmcHosts string `yaml:"bmcHosts" envconfig:"ECO_CNF_RAN_BMC_HOSTS"`
BmcTimeout string `yaml:"bmcTimeout" envconfig:"ECO_CNF_RAN_BMC_TIMEOUT"`
OcpUpgradeUpstreamURL string `yaml:"ocpUpgradeUpstreamUrl" envconfig:"ECO_CNF_RAN_OCP_UPGRADE_UPSTREAM_URL"`
PtpOperatorNamespace string `yaml:"ptpOperatorNamespace" envconfig:"ECO_CNF_RAN_PTP_OPERATOR_NAMESPACE"`
TalmPreCachePolicies []string `yaml:"talmPreCachePolicies" envconfig:"ECO_CNF_RAN_TALM_PRECACHE_POLICIES"`
ZtpSiteGenerateImage string `yaml:"ztpSiteGenerateImage" envconfig:"ECO_CNF_RAN_ZTP_SITE_GENERATE_IMAGE"`
}

// HubConfig contains the configuration for the hub cluster, if present.
type HubConfig struct {
HubAPIClient *clients.Settings
HubOCPVersion string
ZTPVersion string
HubOperatorVersions map[ranparam.HubOperatorName]string
HubKubeconfig string `envconfig:"ECO_CNF_RAN_KUBECONFIG_HUB"`
}

// Spoke1Config contains the configuration for the spoke 1 cluster, which should always be present.
type Spoke1Config struct {
Spoke1BMC *bmc.BMC
Spoke1APIClient *clients.Settings
Spoke1Name string
Spoke1OCPVersion string
BMCUsername string `envconfig:"ECO_CNF_RAN_BMC_USERNAME"`
BMCPassword string `envconfig:"ECO_CNF_RAN_BMC_PASSWORD"`
BMCHosts []string `envconfig:"ECO_CNF_RAN_BMC_HOSTS"`
BMCTimeout time.Duration `yaml:"bmcTimeout" envconfig:"ECO_CNF_RAN_BMC_TIMEOUT"`
}

// Spoke2Config contains the configuration for the spoke 2 cluster, if present.
type Spoke2Config struct {
Spoke2APIClient *clients.Settings
Spoke2Name string
Spoke2OCPVersion string
Spoke2Kubeconfig string `envconfig:"ECO_CNF_RAN_KUBECONFIG_SPOKE2"`
}

// NewRANConfig returns an instance of RANConfig.
Expand All @@ -47,24 +80,162 @@ func NewRANConfig() *RANConfig {
baseDir := filepath.Dir(filename)
configFile := filepath.Join(baseDir, PathToDefaultCnfRanParamsFile)

err := readFile(&ranConfig, configFile)
err := readConfig(&ranConfig, configFile)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Error reading config file %s", configFile)
glog.V(ranparam.LogLevel).Infof("Error reading main RAN Config: %v", err)

return nil
}

err = readEnv(&ranConfig)
ranConfig.newHubConfig(configFile)
ranConfig.newSpoke1Config(configFile)
ranConfig.newSpoke2Config(configFile)

return &ranConfig
}

func (ranconfig *RANConfig) newHubConfig(configFile string) {
glog.V(ranparam.LogLevel).Infof("Creating new HubConfig struct from file %s", configFile)

ranconfig.HubConfig = new(HubConfig)

err := readConfig(ranconfig.HubConfig, configFile)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Error reading environment variables")
glog.V(ranparam.LogLevel).Infof("Failed to instantiate HubConfig: %v", err)
}

return nil
if ranconfig.HubConfig.HubKubeconfig == "" {
glog.V(ranparam.LogLevel).Info("No kubeconfig found for hub")

return
}

return &ranConfig
ranconfig.HubConfig.HubAPIClient = clients.New(ranconfig.HubConfig.HubKubeconfig)

ranconfig.HubConfig.HubOCPVersion, err = ranhelper.GetOCPVersion(ranconfig.HubConfig.HubAPIClient)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get OCP version from hub: %v", err)
}

ranconfig.HubConfig.HubOperatorVersions = make(map[ranparam.HubOperatorName]string)

ranconfig.HubConfig.HubOperatorVersions[ranparam.ACM], err = ranhelper.GetOperatorVersionFromCsv(
ranconfig.HubConfig.HubAPIClient, string(ranparam.ACM), ranparam.AcmOperatorNamespace)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get ACM version from hub: %v", err)
}

ranconfig.HubConfig.HubOperatorVersions[ranparam.GitOps], err = ranhelper.GetOperatorVersionFromCsv(
ranconfig.HubConfig.HubAPIClient, string(ranparam.GitOps), ranparam.OpenshiftGitOpsNamespace)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get GitOps version from hub: %v", err)
}

ranconfig.HubConfig.HubOperatorVersions[ranparam.MCE], err = ranhelper.GetOperatorVersionFromCsv(
ranconfig.HubConfig.HubAPIClient, string(ranparam.MCE), ranparam.MceOperatorNamespace)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get MCE version from hub: %v", err)
}

ranconfig.HubConfig.HubOperatorVersions[ranparam.TALM], err = ranhelper.GetOperatorVersionFromCsv(
ranconfig.HubConfig.HubAPIClient, string(ranparam.TALM), ranparam.OpenshiftOperatorNamespace)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get TALM version from hub: %v", err)
}

glog.V(ranparam.LogLevel).Infof("Found operator versions on hub: %v", ranconfig.HubConfig.HubOperatorVersions)

ranconfig.HubConfig.ZTPVersion, err = ranhelper.GetZTPVersionFromArgoCd(
ranconfig.HubConfig.HubAPIClient, ranparam.OpenshiftGitopsRepoServer, ranparam.OpenshiftGitOpsNamespace)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get ZTP version from hub: %v", err)
}

glog.V(ranparam.LogLevel).Infof("Found ZTP version on hub: %s", ranconfig.HubConfig.ZTPVersion)
}

func (ranconfig *RANConfig) newSpoke1Config(configFile string) {
glog.V(ranparam.LogLevel).Infof("Creating new Spoke1Config struct from file %s", configFile)

ranconfig.Spoke1Config = new(Spoke1Config)

err := readConfig(ranconfig.Spoke1Config, configFile)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to instantiate Spoke1Config: %v", err)
}

ranconfig.Spoke1Config.Spoke1APIClient = inittools.APIClient

spoke1Kubeconfig := os.Getenv("KUBECONFIG")
if spoke1Kubeconfig != "" {
ranconfig.Spoke1Config.Spoke1Name, err = ranhelper.GetClusterName(spoke1Kubeconfig)

if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get spoke 1 name from kubeconfig at %s: %v", spoke1Kubeconfig, err)
}
} else {
glog.V(ranparam.LogLevel).Infof("No spoke 1 kubeconfig specified in KUBECONFIG environment variable")
}

ranconfig.Spoke1Config.Spoke1OCPVersion, err = ranhelper.GetOCPVersion(ranconfig.Spoke1Config.Spoke1APIClient)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get OCP version from spoke 1: %v", err)
}

if len(ranconfig.Spoke1Config.BMCHosts) > 0 &&
ranconfig.Spoke1Config.BMCUsername != "" &&
ranconfig.Spoke1Config.BMCPassword != "" {
bmcHost := ranconfig.Spoke1Config.BMCHosts[0]
if len(ranconfig.Spoke1Config.BMCHosts) > 1 {
glog.V(ranparam.LogLevel).Infof("Found more than one BMC host, using the first one: %s", bmcHost)
}

ranconfig.Spoke1Config.Spoke1BMC = bmc.New(bmcHost).
WithRedfishUser(ranconfig.Spoke1Config.BMCUsername, ranconfig.Spoke1Config.BMCPassword).
WithRedfishTimeout(ranconfig.Spoke1Config.BMCTimeout)
}
}

func (ranconfig *RANConfig) newSpoke2Config(configFile string) {
glog.V(ranparam.LogLevel).Infof("Creating new Spoke2Config struct from file %s", configFile)

ranconfig.Spoke2Config = new(Spoke2Config)

err := readConfig(ranconfig.Spoke2Config, configFile)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to instantiate Spoke2Config: %v", err)
}

if ranconfig.Spoke2Config.Spoke2Kubeconfig == "" {
glog.V(ranparam.LogLevel).Info("No kubeconfig found for spoke 2")

return
}

ranconfig.Spoke2Config.Spoke2APIClient = clients.New(ranconfig.Spoke2Config.Spoke2Kubeconfig)

ranconfig.Spoke2Config.Spoke2Name, err = ranhelper.GetClusterName(ranconfig.Spoke2Config.Spoke2Kubeconfig)
if err != nil {
glog.V(ranparam.LogLevel).Infof(
"Failed to get spoke 2 name from kubeconfig at %s: %v", ranconfig.Spoke2Config.Spoke2Kubeconfig, err)
}

ranconfig.Spoke2Config.Spoke2OCPVersion, err = ranhelper.GetOCPVersion(ranconfig.Spoke2Config.Spoke2APIClient)
if err != nil {
glog.V(ranparam.LogLevel).Infof("Failed to get OCP version from spoke 2: %v", err)
}
}

func readConfig[C any](config *C, configFile string) error {
err := readFile(config, configFile)
if err != nil {
return err
}

return readEnv(config)
}

func readFile(ranConfig *RANConfig, configFile string) error {
func readFile[C any](config *C, configFile string) error {
openedConfigFile, err := os.Open(configFile)
if err != nil {
return err
Expand All @@ -76,13 +247,13 @@ func readFile(ranConfig *RANConfig, configFile string) error {

decoder := yaml.NewDecoder(openedConfigFile)

err = decoder.Decode(&ranConfig)
err = decoder.Decode(config)

return err
}

func readEnv(ranConfig *RANConfig) error {
err := envconfig.Process("", ranConfig)
func readEnv[C any](config *C) error {
err := envconfig.Process("", config)

return err
}
1 change: 1 addition & 0 deletions tests/cnf/ran/internal/ranconfig/default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ ptpOperatorNamespace: "openshift-ptp"
talmPreCachePolicies:
- "common-config-policy"
- "common-subscriptions-policy"
ztpSiteGenerateImage: "registry-proxy.engineering.redhat.com/rh-osbs/openshift4-ztp-site-generate"
...
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package helper
package ranhelper

import (
"github.com/golang/glog"
"github.com/openshift-kni/eco-goinfra/pkg/pod"
"github.com/openshift-kni/eco-gotests/tests/cnf/ran/internal/ranparam"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
)

// IsPodHealthy returns true if a given pod is healthy, otherwise false.
Expand Down Expand Up @@ -41,6 +43,25 @@ func DoesContainerExistInPod(pod *pod.Builder, containerName string) bool {
return false
}

// UnmarshalRaw converts raw bytes for a K8s CR into the actual type.
func UnmarshalRaw[T any](raw []byte) (*T, error) {
untyped := &unstructured.Unstructured{}
err := untyped.UnmarshalJSON(raw)

if err != nil {
return nil, err
}

var typed T
err = runtime.DefaultUnstructuredConverter.FromUnstructured(untyped.UnstructuredContent(), &typed)

if err != nil {
return nil, err
}

return &typed, nil
}

// isPodInCondition returns true if a given pod is in expected condition, otherwise false.
func isPodInCondition(pod *pod.Builder, condition v1.PodConditionType) bool {
for _, c := range pod.Object.Status.Conditions {
Expand Down
Loading

0 comments on commit ae26fd1

Please sign in to comment.