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 }