github.com/openshift/installer@v1.4.17/pkg/asset/agent/image/ignition_test.go (about)

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"os"
     8  	"os/exec"
     9  	"path"
    10  	"strings"
    11  	"testing"
    12  
    13  	igntypes "github.com/coreos/ignition/v2/config/v3_2/types"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/vincent-petithory/dataurl"
    16  	v1 "k8s.io/api/core/v1"
    17  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    18  
    19  	hiveext "github.com/openshift/assisted-service/api/hiveextension/v1beta1"
    20  	aiv1beta1 "github.com/openshift/assisted-service/api/v1beta1"
    21  	"github.com/openshift/assisted-service/models"
    22  	hivev1 "github.com/openshift/hive/apis/hive/v1"
    23  	"github.com/openshift/installer/pkg/asset"
    24  	"github.com/openshift/installer/pkg/asset/agent/agentconfig"
    25  	"github.com/openshift/installer/pkg/asset/agent/common"
    26  	"github.com/openshift/installer/pkg/asset/agent/gencrypto"
    27  	"github.com/openshift/installer/pkg/asset/agent/joiner"
    28  	"github.com/openshift/installer/pkg/asset/agent/manifests"
    29  	"github.com/openshift/installer/pkg/asset/agent/mirror"
    30  	"github.com/openshift/installer/pkg/asset/agent/workflow"
    31  	"github.com/openshift/installer/pkg/asset/password"
    32  	"github.com/openshift/installer/pkg/asset/tls"
    33  	"github.com/openshift/installer/pkg/types/agent"
    34  )
    35  
    36  // Unable to test Generate because bootstrap.AddStorageFiles
    37  // returns error in unit test:
    38  //   open data/agent/files: no such file or directory
    39  // Unit test working directory is ./pkg/asset/agent/image
    40  // While normal execution working directory is ./data
    41  // func TestIgnition_Generate(t *testing.T) {}
    42  
    43  func TestIgnition_getTemplateData(t *testing.T) {
    44  	clusterImageSet := &hivev1.ClusterImageSet{
    45  		ObjectMeta: metav1.ObjectMeta{
    46  			Name: "openshift-v4.10.0",
    47  		},
    48  		Spec: hivev1.ClusterImageSetSpec{
    49  			ReleaseImage: "quay.io:443/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64",
    50  		},
    51  	}
    52  	pullSecret := "pull-secret"
    53  	agentClusterInstall := &hiveext.AgentClusterInstall{
    54  		ObjectMeta: metav1.ObjectMeta{
    55  			Name:      "test-agent-cluster-install",
    56  			Namespace: "cluster0",
    57  		},
    58  		Spec: hiveext.AgentClusterInstallSpec{
    59  			APIVIP:       "192.168.111.2",
    60  			SSHPublicKey: "ssh-rsa AAAAmyKey",
    61  			ProvisionRequirements: hiveext.ProvisionRequirements{
    62  				ControlPlaneAgents: 3,
    63  				WorkerAgents:       5,
    64  			},
    65  		},
    66  	}
    67  	releaseImage := "quay.io:443/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64"
    68  	releaseImageMirror := "virthost.ostest.test.metalkube.org:5000/localimages/local-release-image"
    69  	infraEnvID := "random-infra-env-id"
    70  	haveMirrorConfig := true
    71  	publicContainerRegistries := "quay.io,registry.ci.openshift.org"
    72  
    73  	releaseImageList, err := releaseImageList(clusterImageSet.Spec.ReleaseImage, "x86_64", []string{"86_64"})
    74  	assert.NoError(t, err)
    75  
    76  	arch := "x86_64"
    77  	ov := "4.12"
    78  	isoURL := "https://rhcos.mirror.openshift.com/art/storage/releases/rhcos-4.12/412.86.202208101039-0/x86_64/rhcos-412.86.202208101039-0-live.x86_64.iso"
    79  	ver := "412.86.202208101039-0"
    80  	osImage := &models.OsImage{
    81  		CPUArchitecture:  &arch,
    82  		OpenshiftVersion: &ov,
    83  		URL:              &isoURL,
    84  		Version:          &ver,
    85  	}
    86  
    87  	proxy := &aiv1beta1.Proxy{
    88  		HTTPProxy:  "http://1.1.1.1:80",
    89  		HTTPSProxy: "https://1.1.1.1:443",
    90  		NoProxy:    "valid-proxy.com,172.30.0.0/16",
    91  	}
    92  	clusterName := "test-agent-cluster-install.test"
    93  
    94  	publicKey := "-----BEGIN EC PUBLIC KEY-----\nMHcCAQEEIOSCfDNmx0qe6dncV4tg==\n-----END EC PUBLIC KEY-----\n"
    95  	token := "someToken"
    96  	templateData := getTemplateData(clusterName, pullSecret, releaseImageList, releaseImage, releaseImageMirror, publicContainerRegistries, "minimal-iso", infraEnvID, publicKey, gencrypto.AuthType, token, "", "", haveMirrorConfig, agentClusterInstall.Spec.ProvisionRequirements.ControlPlaneAgents, agentClusterInstall.Spec.ProvisionRequirements.WorkerAgents, osImage, proxy)
    97  	assert.Equal(t, clusterName, templateData.ClusterName)
    98  	assert.Equal(t, "http", templateData.ServiceProtocol)
    99  	assert.Equal(t, pullSecret, templateData.PullSecret)
   100  	assert.Equal(t, agentClusterInstall.Spec.ProvisionRequirements.ControlPlaneAgents, templateData.ControlPlaneAgents)
   101  	assert.Equal(t, agentClusterInstall.Spec.ProvisionRequirements.WorkerAgents, templateData.WorkerAgents)
   102  	assert.Equal(t, releaseImageList, templateData.ReleaseImages)
   103  	assert.Equal(t, releaseImage, templateData.ReleaseImage)
   104  	assert.Equal(t, releaseImageMirror, templateData.ReleaseImageMirror)
   105  	assert.Equal(t, haveMirrorConfig, templateData.HaveMirrorConfig)
   106  	assert.Equal(t, publicContainerRegistries, templateData.PublicContainerRegistries)
   107  	assert.Equal(t, infraEnvID, templateData.InfraEnvID)
   108  	assert.Equal(t, osImage, templateData.OSImage)
   109  	assert.Equal(t, proxy, templateData.Proxy)
   110  	assert.Equal(t, publicKey, templateData.PublicKeyPEM)
   111  	assert.Equal(t, gencrypto.AuthType, templateData.AuthType)
   112  	assert.Equal(t, token, templateData.Token)
   113  
   114  }
   115  
   116  func TestIgnition_getRendezvousHostEnv(t *testing.T) {
   117  	nodeZeroIP := "2001:db8::dead:beef"
   118  	token := "someToken"
   119  	rendezvousHostEnv := getRendezvousHostEnv("http", nodeZeroIP, token, workflow.AgentWorkflowTypeInstall)
   120  	assert.Equal(t,
   121  		"NODE_ZERO_IP="+nodeZeroIP+"\nSERVICE_BASE_URL=http://["+nodeZeroIP+"]:8090/\nIMAGE_SERVICE_BASE_URL=http://["+nodeZeroIP+"]:8888/\nAGENT_AUTH_TOKEN="+token+"\nPULL_SECRET_TOKEN="+token+"\nWORKFLOW_TYPE=install\n",
   122  		rendezvousHostEnv)
   123  }
   124  
   125  func TestIgnition_addStaticNetworkConfig(t *testing.T) {
   126  	_, execErr := exec.LookPath("nmstatectl")
   127  	if execErr != nil {
   128  		t.Skip("No nmstatectl binary available")
   129  	}
   130  
   131  	cases := []struct {
   132  		Name                string
   133  		staticNetworkConfig []*models.HostStaticNetworkConfig
   134  		expectedError       string
   135  		expectedFileList    []string
   136  	}{
   137  		{
   138  			Name: "default",
   139  			staticNetworkConfig: []*models.HostStaticNetworkConfig{
   140  				{
   141  					MacInterfaceMap: models.MacInterfaceMap{
   142  						{LogicalNicName: "eth0", MacAddress: "52:54:01:aa:aa:a1"},
   143  					},
   144  					NetworkYaml: "interfaces:\n- ipv4:\n    address:\n    - ip: 192.168.122.21\n      prefix-length: 24\n    enabled: true\n  mac-address: 52:54:01:aa:aa:a1\n  name: eth0\n  state: up\n  type: ethernet\n",
   145  				},
   146  			},
   147  			expectedError: "",
   148  			expectedFileList: []string{
   149  				"/etc/assisted/network/host0/eth0.nmconnection",
   150  				"/etc/assisted/network/host0/mac_interface.ini",
   151  				"/usr/local/bin/pre-network-manager-config.sh",
   152  			},
   153  		},
   154  		{
   155  			Name:                "no-static-network-configs",
   156  			staticNetworkConfig: []*models.HostStaticNetworkConfig{},
   157  			expectedError:       "",
   158  			expectedFileList:    nil,
   159  		},
   160  		{
   161  			Name: "error-processing-config",
   162  			staticNetworkConfig: []*models.HostStaticNetworkConfig{
   163  				{
   164  					MacInterfaceMap: models.MacInterfaceMap{
   165  						{LogicalNicName: "eth0", MacAddress: "52:54:01:aa:aa:a1"},
   166  					},
   167  					NetworkYaml: "interfaces:\n- ipv4:\n    address:\n    - ip: bad-ip\n      prefix-length: 24\n    enabled: true\n  mac-address: 52:54:01:aa:aa:a1\n  name: eth0\n  state: up\n  type: ethernet\n",
   168  				},
   169  			},
   170  			expectedError:    ".*invalid IP address syntax",
   171  			expectedFileList: nil,
   172  		},
   173  	}
   174  
   175  	for _, tc := range cases {
   176  		t.Run(tc.Name, func(t *testing.T) {
   177  			config := igntypes.Config{}
   178  			err := addStaticNetworkConfig(&config, tc.staticNetworkConfig)
   179  
   180  			if tc.expectedError != "" {
   181  				assert.Regexp(t, tc.expectedError, err.Error())
   182  			} else {
   183  				assert.NoError(t, err)
   184  			}
   185  
   186  			var fileList []string
   187  			for _, file := range config.Storage.Files {
   188  				fileList = append(fileList, file.Node.Path)
   189  			}
   190  			assert.Equal(t, tc.expectedFileList, fileList)
   191  		})
   192  	}
   193  }
   194  
   195  func TestRetrieveRendezvousIP(t *testing.T) {
   196  	rawConfig := `interfaces:
   197    - ipv4:
   198        address:
   199          - ip: "192.168.122.21"`
   200  	cases := []struct {
   201  		Name                 string
   202  		agentConfig          *agent.Config
   203  		nmStateConfigs       []*aiv1beta1.NMStateConfig
   204  		expectedRendezvousIP string
   205  		expectedError        string
   206  	}{
   207  		{
   208  			Name: "valid-agent-config-provided-with-RendezvousIP",
   209  			agentConfig: &agent.Config{
   210  				RendezvousIP: "192.168.122.21",
   211  				Hosts: []agent.Host{
   212  					{
   213  						Hostname: "control-0.example.org",
   214  						Role:     "master",
   215  					},
   216  				},
   217  			},
   218  			expectedRendezvousIP: "192.168.122.21",
   219  		},
   220  		{
   221  			Name: "no-agent-config-provided-so-read-from-nmstateconfig",
   222  			nmStateConfigs: []*aiv1beta1.NMStateConfig{
   223  				{
   224  					Spec: aiv1beta1.NMStateConfigSpec{
   225  						NetConfig: aiv1beta1.NetConfig{
   226  							Raw: []byte(rawConfig),
   227  						},
   228  					},
   229  				},
   230  			},
   231  			expectedRendezvousIP: "192.168.122.21",
   232  		},
   233  		{
   234  			Name: "neither-agent-config-was-provided-with-RendezvousIP-nor-nmstateconfig-manifest",
   235  			agentConfig: &agent.Config{
   236  				Hosts: []agent.Host{
   237  					{
   238  						Hostname: "control-0.example.org",
   239  						Role:     "master",
   240  					},
   241  				},
   242  			},
   243  			expectedError: "missing rendezvousIP in agent-config, at least one host networkConfig, or at least one NMStateConfig manifest",
   244  		},
   245  		{
   246  			Name: "non-canonical-ipv6-address",
   247  			agentConfig: &agent.Config{
   248  				RendezvousIP: "fd2e:6f44:5dd8:c956:0000:0000:0000:0050",
   249  				Hosts: []agent.Host{
   250  					{
   251  						Hostname: "control-0.example.org",
   252  						Role:     "master",
   253  					},
   254  				},
   255  			},
   256  			expectedRendezvousIP: "fd2e:6f44:5dd8:c956::50",
   257  		},
   258  		{
   259  			Name: "invalid-ipv6-address",
   260  			agentConfig: &agent.Config{
   261  				RendezvousIP: "fd2e:6f44:5dd8:c956::0000::0050",
   262  				Hosts: []agent.Host{
   263  					{
   264  						Hostname: "control-0.example.org",
   265  						Role:     "master",
   266  					},
   267  				},
   268  			},
   269  			expectedError: "invalid rendezvous IP: fd2e:6f44:5dd8:c956::0000::0050",
   270  		},
   271  	}
   272  	for _, tc := range cases {
   273  		t.Run(tc.Name, func(t *testing.T) {
   274  			var hosts []agent.Host
   275  			if tc.agentConfig != nil {
   276  				hosts = tc.agentConfig.Hosts
   277  			}
   278  			rendezvousIP, err := RetrieveRendezvousIP(tc.agentConfig, hosts, tc.nmStateConfigs)
   279  			if tc.expectedError != "" {
   280  				assert.Regexp(t, tc.expectedError, err.Error())
   281  			} else {
   282  				assert.NoError(t, err)
   283  				assert.Equal(t, tc.expectedRendezvousIP, rendezvousIP)
   284  			}
   285  		})
   286  	}
   287  }
   288  
   289  func TestAddHostConfig_Roles(t *testing.T) {
   290  	cases := []struct {
   291  		Name                            string
   292  		agentHosts                      *agentconfig.AgentHosts
   293  		expectedNumberOfHostConfigFiles int
   294  	}{
   295  		{
   296  			Name: "one-host-role-defined",
   297  			agentHosts: &agentconfig.AgentHosts{
   298  				Hosts: []agent.Host{
   299  					{
   300  						Role: "master",
   301  					},
   302  				},
   303  			},
   304  			expectedNumberOfHostConfigFiles: 1,
   305  		},
   306  		{
   307  			Name: "multiple-host-roles-defined",
   308  			agentHosts: &agentconfig.AgentHosts{
   309  				Hosts: []agent.Host{
   310  					{
   311  						Role: "master",
   312  					},
   313  					{
   314  						Role: "master",
   315  					},
   316  					{
   317  						Role: "master",
   318  					},
   319  					{
   320  						Role: "worker",
   321  					},
   322  					{
   323  						Role: "worker",
   324  					},
   325  				},
   326  			},
   327  			expectedNumberOfHostConfigFiles: 5,
   328  		},
   329  		{
   330  			Name:                            "zero-host-roles-defined",
   331  			expectedNumberOfHostConfigFiles: 0,
   332  		},
   333  	}
   334  	for _, tc := range cases {
   335  		t.Run(tc.Name, func(t *testing.T) {
   336  			config := &igntypes.Config{}
   337  			err := addHostConfig(config, tc.agentHosts)
   338  			assert.NoError(t, err)
   339  			assert.Equal(t, len(config.Storage.Files), tc.expectedNumberOfHostConfigFiles)
   340  			for _, file := range config.Storage.Files {
   341  				assert.Equal(t, true, strings.HasPrefix(file.Path, "/etc/assisted/hostconfig"))
   342  				assert.Equal(t, true, strings.HasSuffix(file.Path, "role"))
   343  			}
   344  		})
   345  	}
   346  }
   347  
   348  func generatedFiles(otherFiles ...string) []string {
   349  	files := []string{
   350  		"/etc/assisted/rendezvous-host.env",
   351  		"/etc/assisted/manifests/agent-config.yaml",
   352  		// TODO: ZTP manifest files should also be present. Bug?
   353  		// "/etc/assisted/manifests/cluster-deployment.yaml",
   354  		// "/etc/assisted/manifests/agent-cluster-install.yaml",
   355  		// "/etc/assisted/manifests/pull-secret.yaml",
   356  		// "/etc/assisted/manifests/cluster-image-set.yaml",
   357  		// "/etc/assisted/manifests/infraenv.yaml",
   358  		"/etc/assisted/network/host0/eth0.nmconnection",
   359  		"/etc/assisted/network/host0/mac_interface.ini",
   360  		"/usr/local/bin/pre-network-manager-config.sh",
   361  		"/opt/agent/tls/kubeadmin-password.hash"}
   362  	files = append(files, otherFiles...)
   363  	return append(files, commonFiles()...)
   364  }
   365  
   366  func commonFiles() []string {
   367  	return []string{
   368  		"/etc/issue",
   369  		"/etc/multipath.conf",
   370  		"/etc/containers/containers.conf",
   371  		"/etc/NetworkManager/conf.d/clientid.conf",
   372  		"/root/.docker/config.json",
   373  		"/root/assisted.te",
   374  		"/usr/local/bin/agent-config-image-wait.sh",
   375  		"/usr/local/bin/agent-gather",
   376  		"/usr/local/bin/extract-agent.sh",
   377  		"/usr/local/bin/get-container-images.sh",
   378  		"/usr/local/bin/set-hostname.sh",
   379  		"/usr/local/bin/start-agent.sh",
   380  		"/usr/local/bin/start-cluster-installation.sh",
   381  		"/usr/local/bin/wait-for-assisted-service.sh",
   382  		"/usr/local/bin/set-node-zero.sh",
   383  		"/usr/local/share/assisted-service/assisted-db.env",
   384  		"/usr/local/share/assisted-service/assisted-service.env",
   385  		"/usr/local/share/start-cluster/start-cluster.env",
   386  		"/usr/local/share/assisted-service/images.env",
   387  		"/usr/local/bin/bootstrap-service-record.sh",
   388  		"/usr/local/bin/release-image.sh",
   389  		"/usr/local/bin/release-image-download.sh",
   390  		"/etc/assisted/agent-installer.env",
   391  		"/etc/motd.d/10-agent-installer",
   392  		"/etc/systemd/system.conf.d/10-default-env.conf",
   393  		"/usr/local/bin/install-status.sh",
   394  		"/usr/local/bin/issue_status.sh",
   395  		"/usr/local/bin/load-config-iso.sh",
   396  		"/etc/udev/rules.d/80-agent-config-image.rules",
   397  		"/usr/local/bin/add-node.sh",
   398  		"/usr/local/bin/agent-auth-token-status.sh",
   399  		"/usr/local/bin/common.sh",
   400  	}
   401  }
   402  
   403  func TestIgnition_Generate(t *testing.T) {
   404  	skipTestIfnmstatectlIsMissing(t)
   405  
   406  	// This patch currently allows testing the Ignition asset using the embedded resources.
   407  	// TODO: Replace it by mocking the filesystem in bootstrap.AddStorageFiles()
   408  	workingDirectory, err := os.Getwd()
   409  	assert.NoError(t, err)
   410  	err = os.Chdir(path.Join(workingDirectory, "../../../../data"))
   411  	assert.NoError(t, err)
   412  
   413  	secretDataBytes, err := base64.StdEncoding.DecodeString("c3VwZXItc2VjcmV0Cg==")
   414  	assert.NoError(t, err)
   415  
   416  	cases := []struct {
   417  		name                string
   418  		overrideDeps        []asset.Asset
   419  		expectedError       string
   420  		expectedFiles       []string
   421  		expectedFileContent map[string]string
   422  		serviceEnabledMap   map[string]bool
   423  	}{
   424  		{
   425  			name: "no-extra-manifests",
   426  			serviceEnabledMap: map[string]bool{
   427  				"pre-network-manager-config.service": true,
   428  				"agent-check-config-image.service":   false},
   429  			expectedFiles: generatedFiles(),
   430  		},
   431  		{
   432  			name: "default",
   433  			overrideDeps: []asset.Asset{
   434  				&manifests.ExtraManifests{
   435  					FileList: []*asset.File{
   436  						{
   437  							Filename: "openshift/test-configmap.yaml",
   438  							Data: []byte(`
   439  ---
   440  apiVersion: v1
   441  kind: ConfigMap
   442  metadata:
   443    name: agent-test-1
   444  
   445  ---
   446  apiVersion: v1
   447  kind: ConfigMap
   448  metadata:
   449    name: agent-test-2`),
   450  						},
   451  					},
   452  				},
   453  			},
   454  			expectedFiles: generatedFiles("/etc/assisted/extra-manifests/test-configmap-0.yaml", "/etc/assisted/extra-manifests/test-configmap-1.yaml"),
   455  			expectedFileContent: map[string]string{
   456  				"/etc/assisted/extra-manifests/test-configmap-0.yaml": `apiVersion: v1
   457  kind: ConfigMap
   458  metadata:
   459    name: agent-test-1`,
   460  				"/etc/assisted/extra-manifests/test-configmap-1.yaml": `apiVersion: v1
   461  kind: ConfigMap
   462  metadata:
   463    name: agent-test-2
   464  `,
   465  			},
   466  			serviceEnabledMap: map[string]bool{
   467  				"pre-network-manager-config.service": true,
   468  				"agent-check-config-image.service":   false},
   469  		},
   470  		{
   471  			name: "no nmstateconfigs defined, pre-network-manager-config.service should not be enabled",
   472  			overrideDeps: []asset.Asset{
   473  				&manifests.AgentManifests{
   474  					InfraEnv: &aiv1beta1.InfraEnv{
   475  						Spec: aiv1beta1.InfraEnvSpec{
   476  							SSHAuthorizedKey: "my-ssh-key",
   477  						},
   478  					},
   479  					ClusterImageSet: &hivev1.ClusterImageSet{
   480  						Spec: hivev1.ClusterImageSetSpec{
   481  							ReleaseImage: "registry.ci.openshift.org/origin/release:4.11",
   482  						},
   483  					},
   484  					ClusterDeployment: &hivev1.ClusterDeployment{
   485  						Spec: hivev1.ClusterDeploymentSpec{
   486  							ClusterName: "ostest",
   487  							BaseDomain:  "ostest",
   488  						},
   489  					},
   490  					PullSecret: &v1.Secret{
   491  						Data: map[string][]byte{
   492  							".dockerconfigjson": secretDataBytes,
   493  						},
   494  					},
   495  					AgentClusterInstall: &hiveext.AgentClusterInstall{
   496  						Spec: hiveext.AgentClusterInstallSpec{
   497  							APIVIP: "192.168.111.5",
   498  							ProvisionRequirements: hiveext.ProvisionRequirements{
   499  								ControlPlaneAgents: 3,
   500  								WorkerAgents:       5,
   501  							},
   502  						},
   503  					},
   504  				},
   505  			},
   506  			serviceEnabledMap: map[string]bool{
   507  				"pre-network-manager-config.service": false},
   508  		},
   509  	}
   510  	for _, tc := range cases {
   511  		t.Run(tc.name, func(t *testing.T) {
   512  			deps := buildIgnitionAssetDefaultDependencies(t)
   513  
   514  			overrideDeps(deps, tc.overrideDeps)
   515  
   516  			parents := asset.Parents{}
   517  			parents.Add(deps...)
   518  
   519  			ignitionAsset := &Ignition{}
   520  			err := ignitionAsset.Generate(context.Background(), parents)
   521  
   522  			if tc.expectedError != "" {
   523  				assert.Equal(t, tc.expectedError, err.Error())
   524  			} else {
   525  				assert.NoError(t, err)
   526  
   527  				assert.Len(t, ignitionAsset.Config.Storage.Directories, 1)
   528  				assert.Equal(t, "/etc/assisted/extra-manifests", ignitionAsset.Config.Storage.Directories[0].Node.Path)
   529  
   530  				assertExpectedFiles(t, ignitionAsset.Config, tc.expectedFiles, tc.expectedFileContent)
   531  
   532  				assertServiceEnabled(t, ignitionAsset.Config, tc.serviceEnabledMap)
   533  			}
   534  		})
   535  	}
   536  }
   537  
   538  func skipTestIfnmstatectlIsMissing(t *testing.T) {
   539  	t.Helper()
   540  	// Generate calls addStaticNetworkConfig which calls nmstatectl
   541  	_, execErr := exec.LookPath("nmstatectl")
   542  	if execErr != nil {
   543  		t.Skip("No nmstatectl binary available")
   544  	}
   545  }
   546  
   547  func overrideDeps(deps []asset.Asset, overrides []asset.Asset) {
   548  	for _, od := range overrides {
   549  		for i, d := range deps {
   550  			if d.Name() == od.Name() {
   551  				deps[i] = od
   552  				break
   553  			}
   554  		}
   555  	}
   556  }
   557  
   558  func assertServiceEnabled(t *testing.T, config *igntypes.Config, serviceEnabledMap map[string]bool) {
   559  	t.Helper()
   560  	for serviceName, enabled := range serviceEnabledMap {
   561  		for _, unit := range config.Systemd.Units {
   562  			if unit.Name == serviceName {
   563  				if unit.Enabled == nil {
   564  					assert.Equal(t, enabled, false)
   565  				} else {
   566  					assert.Equal(t, enabled, *unit.Enabled)
   567  				}
   568  			}
   569  		}
   570  	}
   571  }
   572  
   573  func assertExpectedFiles(t *testing.T, config *igntypes.Config, expectedFiles []string, expectedFileContent map[string]string) {
   574  	t.Helper()
   575  	if len(expectedFiles) > 0 {
   576  		assert.Equal(t, len(expectedFiles), len(config.Storage.Files))
   577  
   578  		for _, f := range expectedFiles {
   579  			found := false
   580  			for _, i := range config.Storage.Files {
   581  				if i.Node.Path == f {
   582  					if expectedData, ok := expectedFileContent[i.Node.Path]; ok {
   583  						actualData, err := dataurl.DecodeString(*i.FileEmbedded1.Contents.Source)
   584  						assert.NoError(t, err)
   585  						assert.Regexp(t, expectedData, string(actualData.Data))
   586  					}
   587  
   588  					found = true
   589  					break
   590  				}
   591  			}
   592  			assert.True(t, found, fmt.Sprintf("Expected file %s not found", f))
   593  		}
   594  	}
   595  }
   596  
   597  // This test util create the minimum valid set of dependencies for the
   598  // Ignition asset
   599  func buildIgnitionAssetDefaultDependencies(t *testing.T) []asset.Asset {
   600  	t.Helper()
   601  	secretDataBytes, err := base64.StdEncoding.DecodeString("c3VwZXItc2VjcmV0Cg==")
   602  	assert.NoError(t, err)
   603  
   604  	return []asset.Asset{
   605  		&workflow.AgentWorkflow{Workflow: workflow.AgentWorkflowTypeInstall},
   606  		&joiner.ClusterInfo{},
   607  		&joiner.AddNodesConfig{},
   608  		&manifests.AgentManifests{
   609  			InfraEnv: &aiv1beta1.InfraEnv{
   610  				Spec: aiv1beta1.InfraEnvSpec{
   611  					SSHAuthorizedKey: "my-ssh-key",
   612  				},
   613  			},
   614  			ClusterDeployment: &hivev1.ClusterDeployment{
   615  				Spec: hivev1.ClusterDeploymentSpec{
   616  					ClusterName: "ostest",
   617  					BaseDomain:  "ostest",
   618  				},
   619  			},
   620  			ClusterImageSet: &hivev1.ClusterImageSet{
   621  				Spec: hivev1.ClusterImageSetSpec{
   622  					ReleaseImage: "registry.ci.openshift.org/origin/release:4.11",
   623  				},
   624  			},
   625  			PullSecret: &v1.Secret{
   626  				Data: map[string][]byte{
   627  					".dockerconfigjson": secretDataBytes,
   628  				},
   629  			},
   630  			AgentClusterInstall: &hiveext.AgentClusterInstall{
   631  				Spec: hiveext.AgentClusterInstallSpec{
   632  					APIVIP: "192.168.111.5",
   633  					ProvisionRequirements: hiveext.ProvisionRequirements{
   634  						ControlPlaneAgents: 3,
   635  						WorkerAgents:       5,
   636  					},
   637  				},
   638  			},
   639  			NMStateConfigs: []*aiv1beta1.NMStateConfig{
   640  				{
   641  					Spec: aiv1beta1.NMStateConfigSpec{
   642  						Interfaces: []*aiv1beta1.Interface{
   643  							{
   644  								Name:       "eth0",
   645  								MacAddress: "00:01:02:03:04:05",
   646  							},
   647  						},
   648  					},
   649  				},
   650  			},
   651  			StaticNetworkConfigs: []*models.HostStaticNetworkConfig{
   652  				{
   653  					MacInterfaceMap: models.MacInterfaceMap{
   654  						{LogicalNicName: "eth0", MacAddress: "00:01:02:03:04:05"},
   655  					},
   656  					NetworkYaml: "interfaces:\n- ipv4:\n    address:\n    - ip: 192.168.122.21\n      prefix-length: 24\n    enabled: true\n  mac-address: 00:01:02:03:04:05\n  name: eth0\n  state: up\n  type: ethernet\n",
   657  				},
   658  			},
   659  		},
   660  		&agentconfig.AgentConfig{
   661  			Config: &agent.Config{
   662  				RendezvousIP: "192.168.111.80",
   663  			},
   664  			File: &asset.File{
   665  				Filename: "/cluster-manifests/agent-config.yaml",
   666  			},
   667  		},
   668  		&agentconfig.AgentHosts{},
   669  		&manifests.ExtraManifests{},
   670  		&mirror.RegistriesConf{},
   671  		&mirror.CaBundle{},
   672  		&password.KubeadminPassword{},
   673  		&tls.KubeAPIServerLBSignerCertKey{},
   674  		&tls.KubeAPIServerLocalhostSignerCertKey{},
   675  		&tls.KubeAPIServerServiceNetworkSignerCertKey{},
   676  		&tls.AdminKubeConfigSignerCertKey{},
   677  		&tls.AdminKubeConfigClientCertKey{},
   678  		&gencrypto.AuthConfig{},
   679  		&common.InfraEnvID{},
   680  	}
   681  }
   682  
   683  func TestIgnition_getMirrorFromRelease(t *testing.T) {
   684  
   685  	cases := []struct {
   686  		name           string
   687  		release        string
   688  		registriesConf mirror.RegistriesConf
   689  		expectedMirror string
   690  	}{
   691  		{
   692  			name:           "no-mirror",
   693  			release:        "registry.ci.openshift.org/ocp/release:latest",
   694  			registriesConf: mirror.RegistriesConf{},
   695  			expectedMirror: "",
   696  		},
   697  		{
   698  			name:    "mirror-no-match",
   699  			release: "registry.ci.openshift.org/ocp/release:4.11.0-0.nightly-foo",
   700  			registriesConf: mirror.RegistriesConf{
   701  				File: &asset.File{
   702  					Filename: "registries.conf",
   703  					Data:     []byte(""),
   704  				},
   705  				MirrorConfig: []mirror.RegistriesConfig{
   706  					{
   707  						Location: "some.registry.org/release",
   708  						Mirror:   "some.mirror.org",
   709  					},
   710  				},
   711  			},
   712  			expectedMirror: "",
   713  		},
   714  		{
   715  			name:    "mirror-match",
   716  			release: "registry.ci.openshift.org/ocp/release:4.11.0-0.nightly-foo",
   717  			registriesConf: mirror.RegistriesConf{
   718  				File: &asset.File{
   719  					Filename: "registries.conf",
   720  					Data:     []byte(""),
   721  				},
   722  				MirrorConfig: []mirror.RegistriesConfig{
   723  					{
   724  						Location: "registry.ci.openshift.org/ocp/release",
   725  						Mirror:   "virthost.ostest.test.metalkube.org:5000/localimages/local-release-image",
   726  					},
   727  				},
   728  			},
   729  			expectedMirror: "virthost.ostest.test.metalkube.org:5000/localimages/local-release-image:4.11.0-0.nightly-foo",
   730  		},
   731  		{
   732  			name:    "mirror-match-with-checksum",
   733  			release: "quay.io/openshift-release-dev/ocp-release@sha256:300bce8246cf880e792e106607925de0a404484637627edf5f517375517d54a4",
   734  			registriesConf: mirror.RegistriesConf{
   735  				File: &asset.File{
   736  					Filename: "registries.conf",
   737  					Data:     []byte(""),
   738  				},
   739  				MirrorConfig: []mirror.RegistriesConfig{
   740  					{
   741  						Location: "quay.io/openshift-release-dev/ocp-v4.0-art-dev",
   742  						Mirror:   "localhost:5000/openshift4/openshift/release",
   743  					},
   744  					{
   745  						Location: "quay.io/openshift-release-dev/ocp-release",
   746  						Mirror:   "localhost:5000/openshift-release-dev/ocp-release",
   747  					},
   748  				},
   749  			},
   750  			expectedMirror: "localhost:5000/openshift-release-dev/ocp-release@sha256:300bce8246cf880e792e106607925de0a404484637627edf5f517375517d54a4",
   751  		},
   752  	}
   753  	for _, tc := range cases {
   754  		t.Run(tc.name, func(t *testing.T) {
   755  
   756  			mirror := mirror.GetMirrorFromRelease(tc.release, &tc.registriesConf)
   757  
   758  			assert.Equal(t, tc.expectedMirror, mirror)
   759  		})
   760  	}
   761  }
   762  
   763  func TestIgnition_getPublicContainerRegistries(t *testing.T) {
   764  
   765  	cases := []struct {
   766  		name               string
   767  		registriesConf     mirror.RegistriesConf
   768  		expectedRegistries string
   769  	}{
   770  		{
   771  			name:               "no-mirror",
   772  			registriesConf:     mirror.RegistriesConf{},
   773  			expectedRegistries: "quay.io",
   774  		},
   775  		{
   776  			name: "mirror-one-entry",
   777  			registriesConf: mirror.RegistriesConf{
   778  				File: &asset.File{
   779  					Filename: "registries.conf",
   780  					Data:     []byte(""),
   781  				},
   782  				MirrorConfig: []mirror.RegistriesConfig{
   783  					{
   784  						Location: "some.registry.org/release",
   785  						Mirror:   "some.mirror.org",
   786  					},
   787  				},
   788  			},
   789  			expectedRegistries: "some.registry.org",
   790  		},
   791  		{
   792  			name: "mirror-multiple-entries",
   793  			registriesConf: mirror.RegistriesConf{
   794  				File: &asset.File{
   795  					Filename: "registries.conf",
   796  					Data:     []byte(""),
   797  				},
   798  				MirrorConfig: []mirror.RegistriesConfig{
   799  					{
   800  						Location: "quay.io/openshift-release-dev/ocp-v4.0-art-dev",
   801  						Mirror:   "localhost:5000/openshift4/openshift/release",
   802  					},
   803  					{
   804  						Location: "registry.ci.openshift.org/ocp/release",
   805  						Mirror:   "localhost:5000/openshift-release-dev/ocp-release",
   806  					},
   807  				},
   808  			},
   809  			expectedRegistries: "quay.io,registry.ci.openshift.org",
   810  		},
   811  		{
   812  			name: "duplicate-entries",
   813  			registriesConf: mirror.RegistriesConf{
   814  				File: &asset.File{
   815  					Filename: "registries.conf",
   816  					Data:     []byte(""),
   817  				},
   818  				MirrorConfig: []mirror.RegistriesConfig{
   819  					{
   820  						Location: "registry.ci.openshift.org/ocp-v4.0-art-dev",
   821  						Mirror:   "localhost:5000/openshift4/openshift/release",
   822  					},
   823  					{
   824  						Location: "registry.ci.openshift.org/ocp/release",
   825  						Mirror:   "localhost:5000/openshift-release-dev/ocp-release",
   826  					},
   827  				},
   828  			},
   829  			expectedRegistries: "registry.ci.openshift.org",
   830  		},
   831  	}
   832  	for _, tc := range cases {
   833  		t.Run(tc.name, func(t *testing.T) {
   834  
   835  			publicContainerRegistries := getPublicContainerRegistries(&tc.registriesConf)
   836  
   837  			assert.Equal(t, tc.expectedRegistries, publicContainerRegistries)
   838  		})
   839  	}
   840  }