github.com/SUSE/skuba@v1.4.17/pkg/skuba/actions/cluster/init/init_test.go (about)

     1  /*
     2   * Copyright (c) 2019 SUSE LLC.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   */
    17  
    18  package cluster
    19  
    20  import (
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"path/filepath"
    25  	"testing"
    26  
    27  	"github.com/SUSE/skuba/internal/pkg/skuba/node"
    28  	constants "github.com/SUSE/skuba/pkg/skuba"
    29  )
    30  
    31  type TestFilesystemContext struct {
    32  	WorkDirectory    string
    33  	OldWorkDirectory string
    34  }
    35  
    36  func TestInitCloudProvider(t *testing.T) {
    37  	tests := []struct {
    38  		name                string
    39  		cloudProvider       string
    40  		providerReadmeFiles []string
    41  	}{
    42  		{
    43  			name:          "init with no cloud provider",
    44  			cloudProvider: "",
    45  			providerReadmeFiles: []string{
    46  				constants.CloudReadmeFile(),
    47  			},
    48  		},
    49  		{
    50  			name:          "init with aws cloud provider",
    51  			cloudProvider: "aws",
    52  			providerReadmeFiles: []string{
    53  				constants.CloudReadmeFile(),
    54  				constants.AWSReadmeFile(),
    55  			},
    56  		},
    57  		{
    58  			name:          "init with opendstack cloud provider",
    59  			cloudProvider: "openstack",
    60  			providerReadmeFiles: []string{
    61  				constants.CloudReadmeFile(),
    62  				constants.OpenstackReadmeFile(),
    63  			},
    64  		},
    65  		{
    66  			name:          "init with vsphere cloud provider",
    67  			cloudProvider: "vsphere",
    68  			providerReadmeFiles: []string{
    69  				constants.CloudReadmeFile(),
    70  				constants.VSphereReadmeFile(),
    71  			},
    72  		},
    73  	}
    74  
    75  	clusterName := "testCluster"
    76  	controlPlane := "http://k8s.example.com"
    77  	k8sDesiredVersion := ""
    78  	strictCapDefaults := true
    79  	initConfig := "kubeadm-init.conf"
    80  	joinFiles := []string{
    81  		filepath.Join("kubeadm-join.conf.d", "master.conf.template"),
    82  		filepath.Join("kubeadm-join.conf.d", "worker.conf.template"),
    83  	}
    84  	for _, tt := range tests {
    85  		tt := tt // Parallel testing
    86  		t.Run(tt.name, func(t *testing.T) {
    87  			initConf, err := NewInitConfiguration(
    88  				clusterName,
    89  				tt.cloudProvider,
    90  				controlPlane,
    91  				k8sDesiredVersion,
    92  				strictCapDefaults)
    93  			if err != nil {
    94  				t.Errorf("unexpected error: %v", err)
    95  			}
    96  
    97  			ctx, err := switchToTemporaryDirectory()
    98  			if err != nil {
    99  				t.Errorf("unexpect error: %v", err)
   100  			}
   101  			defer switchBackAndCleanFilesystem(ctx)
   102  
   103  			if err = Init(initConf); err != nil {
   104  				t.Errorf("unexpect error: %v", err)
   105  			}
   106  
   107  			switch tt.cloudProvider {
   108  			case "":
   109  				for _, file := range tt.providerReadmeFiles {
   110  					found, err := doesFileExist(ctx, clusterName, file)
   111  					if err != nil {
   112  						t.Errorf("unexpected error while checking %s presence: %v",
   113  							file, err)
   114  					}
   115  					if found {
   116  						t.Errorf("unexpected file %s found", file)
   117  					}
   118  				}
   119  			default:
   120  				for _, file := range tt.providerReadmeFiles {
   121  					found, err := doesFileExist(ctx, clusterName, file)
   122  					if err != nil {
   123  						t.Errorf("unexpected error while checking %s presence: %v",
   124  							file, err)
   125  					}
   126  					if !found {
   127  						t.Errorf("expected %s to exist", file)
   128  					}
   129  				}
   130  			}
   131  
   132  			if err := checkInitConfig(ctx, clusterName, initConfig, tt.cloudProvider); err != nil {
   133  				t.Errorf("%s: %v", initConfig, err)
   134  			}
   135  
   136  			for _, f := range joinFiles {
   137  				if err := checkJoinConfig(ctx, clusterName, f, tt.cloudProvider); err != nil {
   138  					t.Errorf("error while inspecting file %s: %v", f, err)
   139  				}
   140  			}
   141  		})
   142  	}
   143  }
   144  
   145  // check the init configuration hold inside of `file`. Path to file is built starting
   146  // from the test `ctx` and the `clusterName`, plus the ending name of the `file`.
   147  // `cloud` holds the name of the CPI - leave empty if CPI is disabled.
   148  func checkInitConfig(ctx TestFilesystemContext, clusterName, file, provider string) error {
   149  	expected := len(provider) > 0
   150  	kubeadmInitConfig, err := node.LoadInitConfigurationFromFile(
   151  		filepath.Join(ctx.WorkDirectory, clusterName, file))
   152  	if err != nil {
   153  		return fmt.Errorf("unexpected error: %v", err)
   154  	}
   155  
   156  	value, found := kubeadmInitConfig.NodeRegistration.KubeletExtraArgs["cloud-provider"]
   157  	if err := checkMapEntry(provider, value, expected, found); err != nil {
   158  		return fmt.Errorf("nodeRegistration  - %v", err)
   159  	}
   160  
   161  	value, found = kubeadmInitConfig.ClusterConfiguration.APIServer.ExtraArgs["cloud-provider"]
   162  	if err := checkMapEntry(provider, value, expected, found); err != nil {
   163  		return fmt.Errorf("apiServer.extraArgs - %v", err)
   164  	}
   165  
   166  	value, found = kubeadmInitConfig.ClusterConfiguration.ControllerManager.ExtraArgs["cloud-provider"]
   167  	if err := checkMapEntry(provider, value, expected, found); err != nil {
   168  		return fmt.Errorf("controllerManager.extraArgs - %v", err)
   169  	}
   170  
   171  	if provider == "aws" {
   172  		value, found = kubeadmInitConfig.ClusterConfiguration.ControllerManager.ExtraArgs["allocate-node-cidrs"]
   173  		if err := checkMapEntry("false", value, expected, found); err != nil {
   174  			return fmt.Errorf("controllerManager.extraArgs - %v", err)
   175  		}
   176  	}
   177  
   178  	return nil
   179  }
   180  
   181  // check the join configuration hold inside of `file`. Path to file is built starting
   182  // from the test `ctx` and the `clusterName`, plus the ending name of the `file`.
   183  // `cloud` holds the name of the CPI - leave empty if CPI is disabled.
   184  func checkJoinConfig(ctx TestFilesystemContext, clusterName, file, provider string) error {
   185  	expected := provider != ""
   186  	kubeadmJoinConfig, err := node.LoadJoinConfigurationFromFile(
   187  		filepath.Join(ctx.WorkDirectory, clusterName, file))
   188  	if err != nil {
   189  		return err
   190  	}
   191  
   192  	value, found := kubeadmJoinConfig.NodeRegistration.KubeletExtraArgs["cloud-provider"]
   193  	return checkMapEntry(provider, value, expected, found)
   194  }
   195  
   196  // Compares the `value` found inside of a map against its `expectedValue`
   197  // return an error when the check fails
   198  func checkMapEntry(expectedValue, value string, expected, found bool) error {
   199  	if found {
   200  		if !expected {
   201  			return fmt.Errorf("cloud-provider integration is accidentally enabled")
   202  		}
   203  		if value != expectedValue {
   204  			return fmt.Errorf("wrong cloud-provider value, expected %s, got %s", expectedValue, value)
   205  		}
   206  	} else if expected {
   207  		return fmt.Errorf("nodeRegistration - couldn't find cloud-provider value")
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  // Create a new temporary directory and switches into it
   214  func switchToTemporaryDirectory() (TestFilesystemContext, error) {
   215  	var ctx TestFilesystemContext
   216  
   217  	tmp, err := os.Getwd()
   218  	if err != nil {
   219  		return ctx, err
   220  	}
   221  	ctx.OldWorkDirectory = tmp
   222  
   223  	tmp, err = ioutil.TempDir("", "skuba-cluster-init-test")
   224  	if err != nil {
   225  		return ctx, err
   226  	}
   227  	ctx.WorkDirectory = tmp
   228  
   229  	if err = os.Chdir(ctx.WorkDirectory); err != nil {
   230  		return ctx, err
   231  	}
   232  
   233  	return ctx, nil
   234  }
   235  
   236  // Remove the temporary directory previously created and
   237  // moves back to the work directory used at the beginning of
   238  // the test
   239  func switchBackAndCleanFilesystem(ctx TestFilesystemContext) {
   240  	if err := os.Chdir(ctx.OldWorkDirectory); err != nil {
   241  		fmt.Printf("Cannot chdir back to original work directory: %v", err)
   242  	}
   243  	if err := os.RemoveAll(ctx.WorkDirectory); err != nil {
   244  		fmt.Printf("Cannot remove temporary directory: %v", err)
   245  	}
   246  }
   247  
   248  // Checks if the specified file exists. Raises an error if something
   249  // unexpected happens.
   250  func doesFileExist(ctx TestFilesystemContext, clusterName, file string) (bool, error) {
   251  	fullpath := filepath.Join(ctx.WorkDirectory, clusterName, file)
   252  	if _, err := os.Stat(fullpath); err != nil {
   253  		if os.IsNotExist(err) {
   254  			return false, nil
   255  		}
   256  		return false, err
   257  	}
   258  
   259  	return true, nil
   260  }