github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/cloud_test.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package provider_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/collections/set"
    10  	"github.com/juju/loggo"
    11  	"github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  	corev1 "k8s.io/api/core/v1"
    15  	storagev1 "k8s.io/api/storage/v1"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  	k8slabels "k8s.io/apimachinery/pkg/labels"
    18  
    19  	"github.com/juju/juju/caas"
    20  	k8s "github.com/juju/juju/caas/kubernetes"
    21  	k8scloud "github.com/juju/juju/caas/kubernetes/cloud"
    22  	"github.com/juju/juju/caas/kubernetes/provider"
    23  	k8sutils "github.com/juju/juju/caas/kubernetes/provider/utils"
    24  	jujucloud "github.com/juju/juju/cloud"
    25  	"github.com/juju/juju/environs"
    26  )
    27  
    28  var _ = gc.Suite(&cloudSuite{})
    29  
    30  type cloudSuite struct {
    31  	fakeBroker fakeK8sClusterMetadataChecker
    32  	runner     dummyRunner
    33  }
    34  
    35  var defaultK8sCloud = jujucloud.Cloud{
    36  	Name:           k8s.K8sCloudMicrok8s,
    37  	Endpoint:       "http://1.1.1.1:8080",
    38  	Type:           jujucloud.CloudTypeKubernetes,
    39  	AuthTypes:      []jujucloud.AuthType{jujucloud.UserPassAuthType},
    40  	CACertificates: []string{""},
    41  	SkipTLSVerify:  true,
    42  }
    43  
    44  var defaultClusterMetadata = &k8s.ClusterMetadata{
    45  	Cloud:   k8s.K8sCloudMicrok8s,
    46  	Regions: set.NewStrings(k8s.Microk8sRegion),
    47  	OperatorStorageClass: &storagev1.StorageClass{
    48  		ObjectMeta: metav1.ObjectMeta{
    49  			Name: "operator-sc",
    50  		},
    51  	},
    52  }
    53  
    54  func getDefaultCredential() jujucloud.Credential {
    55  	defaultCredential := jujucloud.NewCredential(jujucloud.UserPassAuthType, map[string]string{"username": "admin", "password": ""})
    56  	defaultCredential.Label = "kubernetes credential \"admin\""
    57  	return defaultCredential
    58  }
    59  
    60  func (s *cloudSuite) SetUpTest(c *gc.C) {
    61  	var logger loggo.Logger
    62  	s.fakeBroker = fakeK8sClusterMetadataChecker{CallMocker: testing.NewCallMocker(logger)}
    63  	s.runner = dummyRunner{CallMocker: testing.NewCallMocker(logger)}
    64  }
    65  
    66  func (s *cloudSuite) TestFinalizeCloudMicrok8s(c *gc.C) {
    67  	p := s.getProvider()
    68  	cloudFinalizer := p.(environs.CloudFinalizer)
    69  	s.fakeBroker.Call("ListStorageClasses", k8slabels.NewSelector()).Returns(
    70  		[]storagev1.StorageClass{
    71  			{
    72  				ObjectMeta: metav1.ObjectMeta{
    73  					Name: "microk8s-hostpath",
    74  					Annotations: map[string]string{
    75  						"storageclass.kubernetes.io/is-default-class": "true",
    76  					},
    77  				},
    78  			},
    79  		}, nil,
    80  	)
    81  	s.fakeBroker.Call(
    82  		"ListPods", "kube-system",
    83  		k8sutils.LabelsToSelector(map[string]string{"k8s-app": "kube-dns"}),
    84  	).Returns([]corev1.Pod{
    85  		{
    86  			ObjectMeta: metav1.ObjectMeta{
    87  				Name: "coredns-xx",
    88  				Labels: map[string]string{
    89  					"k8s-app": "kube-dns",
    90  				},
    91  			},
    92  		},
    93  	}, nil)
    94  
    95  	var ctx mockContext
    96  	cloud, err := cloudFinalizer.FinalizeCloud(&ctx, defaultK8sCloud)
    97  	c.Assert(err, jc.ErrorIsNil)
    98  	c.Assert(cloud, jc.DeepEquals, jujucloud.Cloud{
    99  		Name:            k8s.K8sCloudMicrok8s,
   100  		Type:            jujucloud.CloudTypeKubernetes,
   101  		AuthTypes:       []jujucloud.AuthType{jujucloud.UserPassAuthType},
   102  		CACertificates:  []string{""},
   103  		SkipTLSVerify:   true,
   104  		Endpoint:        "http://1.1.1.1:8080",
   105  		HostCloudRegion: fmt.Sprintf("%s/%s", k8s.K8sCloudMicrok8s, k8s.Microk8sRegion),
   106  		Config:          map[string]interface{}{"operator-storage": "operator-sc", "workload-storage": ""},
   107  		Regions:         []jujucloud.Region{{Name: k8s.Microk8sRegion, Endpoint: "http://1.1.1.1:8080"}},
   108  	})
   109  }
   110  
   111  func (s *cloudSuite) TestFinalizeCloudMicrok8sAlreadyStorage(c *gc.C) {
   112  	preparedCloud := jujucloud.Cloud{
   113  		Name:            k8s.K8sCloudMicrok8s,
   114  		Type:            jujucloud.CloudTypeKubernetes,
   115  		AuthTypes:       []jujucloud.AuthType{jujucloud.UserPassAuthType},
   116  		CACertificates:  []string{""},
   117  		Endpoint:        "http://1.1.1.1:8080",
   118  		HostCloudRegion: fmt.Sprintf("%s/%s", k8s.K8sCloudMicrok8s, k8s.Microk8sRegion),
   119  		Config:          map[string]interface{}{"operator-storage": "something-else", "workload-storage": ""},
   120  		Regions:         []jujucloud.Region{{Name: k8s.Microk8sRegion, Endpoint: "http://1.1.1.1:8080"}},
   121  	}
   122  
   123  	p := s.getProvider()
   124  	cloudFinalizer := p.(environs.CloudFinalizer)
   125  
   126  	var ctx mockContext
   127  	cloud, err := cloudFinalizer.FinalizeCloud(&ctx, preparedCloud)
   128  	c.Assert(err, jc.ErrorIsNil)
   129  	c.Assert(cloud, jc.DeepEquals, jujucloud.Cloud{
   130  		Name:            k8s.K8sCloudMicrok8s,
   131  		Type:            jujucloud.CloudTypeKubernetes,
   132  		AuthTypes:       k8scloud.SupportedAuthTypes(),
   133  		CACertificates:  []string{""},
   134  		Endpoint:        "http://1.1.1.1:8080",
   135  		HostCloudRegion: fmt.Sprintf("%s/%s", k8s.K8sCloudMicrok8s, k8s.Microk8sRegion),
   136  		Config:          map[string]interface{}{"operator-storage": "something-else", "workload-storage": ""},
   137  		Regions:         []jujucloud.Region{{Name: k8s.Microk8sRegion, Endpoint: "http://1.1.1.1:8080"}},
   138  	})
   139  }
   140  
   141  func (s *cloudSuite) getProvider() caas.ContainerEnvironProvider {
   142  	s.fakeBroker.Call("GetClusterMetadata").Returns(defaultClusterMetadata, nil)
   143  	s.fakeBroker.Call("CheckDefaultWorkloadStorage").Returns(nil)
   144  	ret := builtinCloudRet{cloud: defaultK8sCloud, credential: getDefaultCredential(), err: nil}
   145  	return provider.NewProviderWithFakes(
   146  		s.runner,
   147  		credentialGetterFunc(ret),
   148  		cloudGetterFunc(ret),
   149  		func(environs.OpenParams) (provider.ClusterMetadataStorageChecker, error) { return &s.fakeBroker, nil },
   150  	)
   151  }
   152  
   153  func (s *cloudSuite) TestEnsureMicroK8sSuitableSuccess(c *gc.C) {
   154  	s.fakeBroker.Call("ListStorageClasses", k8slabels.NewSelector()).Returns(
   155  		[]storagev1.StorageClass{
   156  			{
   157  				ObjectMeta: metav1.ObjectMeta{
   158  					Name: "microk8s-hostpath",
   159  					Annotations: map[string]string{
   160  						"storageclass.kubernetes.io/is-default-class": "true",
   161  					},
   162  				},
   163  			},
   164  		}, nil,
   165  	)
   166  	s.fakeBroker.Call(
   167  		"ListPods", "kube-system",
   168  		k8sutils.LabelsToSelector(map[string]string{"k8s-app": "kube-dns"}),
   169  	).Returns([]corev1.Pod{
   170  		{
   171  			ObjectMeta: metav1.ObjectMeta{
   172  				Name: "coredns-xx",
   173  				Labels: map[string]string{
   174  					"k8s-app": "kube-dns",
   175  				},
   176  			},
   177  		},
   178  	}, nil)
   179  	c.Assert(provider.EnsureMicroK8sSuitable(&s.fakeBroker), jc.ErrorIsNil)
   180  }
   181  
   182  func (s *cloudSuite) TestEnsureMicroK8sSuitableStorageNotEnabled(c *gc.C) {
   183  	s.fakeBroker.Call("ListStorageClasses", k8slabels.NewSelector()).Returns(
   184  		[]storagev1.StorageClass{}, nil,
   185  	)
   186  	err := provider.EnsureMicroK8sSuitable(&s.fakeBroker)
   187  	c.Assert(err, gc.ErrorMatches, `required storage addon is not enabled`)
   188  }
   189  
   190  func (s *cloudSuite) TestEnsureMicroK8sSuitableDNSNotEnabled(c *gc.C) {
   191  	s.fakeBroker.Call("ListStorageClasses", k8slabels.NewSelector()).Returns(
   192  		[]storagev1.StorageClass{
   193  			{
   194  				ObjectMeta: metav1.ObjectMeta{
   195  					Name: "microk8s-hostpath",
   196  					Annotations: map[string]string{
   197  						"storageclass.kubernetes.io/is-default-class": "true",
   198  					},
   199  				},
   200  			},
   201  		}, nil,
   202  	)
   203  	s.fakeBroker.Call(
   204  		"ListPods", "kube-system",
   205  		k8sutils.LabelsToSelector(map[string]string{"k8s-app": "kube-dns"}),
   206  	).Returns([]corev1.Pod{}, nil)
   207  	err := provider.EnsureMicroK8sSuitable(&s.fakeBroker)
   208  	c.Assert(err, gc.ErrorMatches, `required dns addon is not enabled`)
   209  }
   210  
   211  type mockContext struct {
   212  	testing.Stub
   213  }
   214  
   215  func (c *mockContext) Verbosef(f string, args ...interface{}) {
   216  	c.MethodCall(c, "Verbosef", f, args)
   217  }
   218  
   219  type fakeK8sClusterMetadataChecker struct {
   220  	*testing.CallMocker
   221  	k8s.ClusterMetadataChecker
   222  }
   223  
   224  func (api *fakeK8sClusterMetadataChecker) GetClusterMetadata(storageClass string) (result *k8s.ClusterMetadata, err error) {
   225  	results := api.MethodCall(api, "GetClusterMetadata")
   226  	return results[0].(*k8s.ClusterMetadata), testing.TypeAssertError(results[1])
   227  }
   228  
   229  func (api *fakeK8sClusterMetadataChecker) CheckDefaultWorkloadStorage(cluster string, storageProvisioner *k8s.StorageProvisioner) error {
   230  	results := api.MethodCall(api, "CheckDefaultWorkloadStorage")
   231  	return testing.TypeAssertError(results[0])
   232  }
   233  
   234  func (api *fakeK8sClusterMetadataChecker) EnsureStorageProvisioner(cfg k8s.StorageProvisioner) (*k8s.StorageProvisioner, bool, error) {
   235  	results := api.MethodCall(api, "EnsureStorageProvisioner")
   236  	return results[0].(*k8s.StorageProvisioner), false, testing.TypeAssertError(results[1])
   237  }
   238  
   239  func (api *fakeK8sClusterMetadataChecker) ListPods(namespace string, selector k8slabels.Selector) ([]corev1.Pod, error) {
   240  	results := api.MethodCall(api, "ListPods", namespace, selector)
   241  	return results[0].([]corev1.Pod), nil
   242  }
   243  
   244  func (api *fakeK8sClusterMetadataChecker) ListStorageClasses(selector k8slabels.Selector) ([]storagev1.StorageClass, error) {
   245  	results := api.MethodCall(api, "ListStorageClasses", selector)
   246  	return results[0].([]storagev1.StorageClass), nil
   247  }