Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cnf ran: ztp test migration preliminaries #72

Merged
merged 1 commit into from
Jul 3, 2024
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
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
Loading