github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/caasoperatorprovisioner/provisioner_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package caasoperatorprovisioner_test 5 6 import ( 7 "crypto/x509" 8 9 "github.com/juju/charm/v12" 10 "github.com/juju/errors" 11 "github.com/juju/names/v5" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/version/v2" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/apiserver/common" 17 "github.com/juju/juju/apiserver/facades/controller/caasoperatorprovisioner" 18 apiservertesting "github.com/juju/juju/apiserver/testing" 19 "github.com/juju/juju/core/life" 20 "github.com/juju/juju/pki" 21 "github.com/juju/juju/rpc/params" 22 "github.com/juju/juju/state" 23 coretesting "github.com/juju/juju/testing" 24 jujuversion "github.com/juju/juju/version" 25 ) 26 27 var _ = gc.Suite(&CAASProvisionerSuite{}) 28 29 type CAASProvisionerSuite struct { 30 coretesting.BaseSuite 31 32 resources *common.Resources 33 authorizer *apiservertesting.FakeAuthorizer 34 api *caasoperatorprovisioner.API 35 st *mockState 36 storagePoolManager *mockStoragePoolManager 37 registry *mockStorageRegistry 38 } 39 40 func (s *CAASProvisionerSuite) SetUpTest(c *gc.C) { 41 s.BaseSuite.SetUpTest(c) 42 43 s.resources = common.NewResources() 44 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 45 s.PatchValue(&jujuversion.OfficialBuild, 0) 46 47 s.authorizer = &apiservertesting.FakeAuthorizer{ 48 Tag: names.NewMachineTag("0"), 49 Controller: true, 50 } 51 52 s.st = newMockState() 53 s.storagePoolManager = &mockStoragePoolManager{} 54 s.registry = &mockStorageRegistry{} 55 api, err := caasoperatorprovisioner.NewCAASOperatorProvisionerAPI( 56 s.resources, s.authorizer, s.st, s.st, s.storagePoolManager, s.registry) 57 c.Assert(err, jc.ErrorIsNil) 58 s.api = api 59 } 60 61 func (s *CAASProvisionerSuite) TestPermission(c *gc.C) { 62 s.authorizer = &apiservertesting.FakeAuthorizer{ 63 Tag: names.NewMachineTag("0"), 64 } 65 _, err := caasoperatorprovisioner.NewCAASOperatorProvisionerAPI( 66 s.resources, s.authorizer, s.st, s.st, s.storagePoolManager, s.registry) 67 c.Assert(err, gc.ErrorMatches, "permission denied") 68 } 69 70 func (s *CAASProvisionerSuite) TestWatchApplications(c *gc.C) { 71 applicationNames := []string{"db2", "hadoop"} 72 s.st.applicationWatcher.changes <- applicationNames 73 result, err := s.api.WatchApplications() 74 c.Assert(err, jc.ErrorIsNil) 75 c.Assert(result.Error, gc.IsNil) 76 c.Assert(result.StringsWatcherId, gc.Equals, "1") 77 c.Assert(result.Changes, jc.DeepEquals, applicationNames) 78 79 resource := s.resources.Get("1") 80 c.Assert(resource, gc.NotNil) 81 c.Assert(resource, gc.Implements, new(state.StringsWatcher)) 82 } 83 84 func (s *CAASProvisionerSuite) TestSetPasswords(c *gc.C) { 85 s.st.app = &mockApplication{ 86 tag: names.NewApplicationTag("app"), 87 } 88 89 args := params.EntityPasswords{ 90 Changes: []params.EntityPassword{ 91 {Tag: "application-app", Password: "xxx-12345678901234567890"}, 92 {Tag: "application-another", Password: "yyy-12345678901234567890"}, 93 {Tag: "machine-0", Password: "zzz-12345678901234567890"}, 94 }, 95 } 96 results, err := s.api.SetPasswords(args) 97 c.Assert(err, jc.ErrorIsNil) 98 c.Assert(results, gc.DeepEquals, params.ErrorResults{ 99 Results: []params.ErrorResult{ 100 {nil}, 101 {¶ms.Error{Message: "entity application-another not found", Code: "not found"}}, 102 {¶ms.Error{Message: "permission denied", Code: "unauthorized access"}}, 103 }, 104 }) 105 c.Assert(s.st.app.password, gc.Equals, "xxx-12345678901234567890") 106 } 107 108 func (s *CAASProvisionerSuite) TestLife(c *gc.C) { 109 s.st.app = &mockApplication{ 110 tag: names.NewApplicationTag("app"), 111 } 112 results, err := s.api.Life(params.Entities{ 113 Entities: []params.Entity{ 114 {Tag: "application-app"}, 115 {Tag: "machine-0"}, 116 }, 117 }) 118 c.Assert(err, jc.ErrorIsNil) 119 c.Assert(results, jc.DeepEquals, params.LifeResults{ 120 Results: []params.LifeResult{{ 121 Life: life.Alive, 122 }, { 123 Error: ¶ms.Error{ 124 Code: "unauthorized access", 125 Message: "permission denied", 126 }, 127 }}, 128 }) 129 } 130 131 func (s *CAASProvisionerSuite) TestOperatorProvisioningInfoDefault(c *gc.C) { 132 s.st.app = &mockApplication{ 133 charm: &mockCharm{meta: &charm.Meta{}}, 134 } 135 result, err := s.api.OperatorProvisioningInfo(params.Entities{Entities: []params.Entity{{"application-gitlab"}}}) 136 c.Assert(err, jc.ErrorIsNil) 137 c.Assert(result, jc.DeepEquals, params.OperatorProvisioningInfoResults{ 138 Results: []params.OperatorProvisioningInfo{{ 139 ImageDetails: params.DockerImageInfo{ 140 RegistryPath: "docker.io/jujusolutions/jujud-operator:2.6-beta3.666", 141 }, 142 BaseImageDetails: params.DockerImageInfo{ 143 RegistryPath: "docker.io/jujusolutions/charm-base:ubuntu-20.04", 144 }, 145 Version: version.MustParse("2.6-beta3.666"), 146 APIAddresses: []string{"10.0.0.1:1"}, 147 Tags: map[string]string{ 148 "juju-model-uuid": coretesting.ModelTag.Id(), 149 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 150 CharmStorage: ¶ms.KubernetesFilesystemParams{ 151 StorageName: "charm", 152 Size: uint64(1024), 153 Provider: "kubernetes", 154 Attributes: map[string]interface{}{ 155 "storage-class": "k8s-storage", 156 "foo": "bar", 157 }, 158 Tags: map[string]string{ 159 "juju-model-uuid": coretesting.ModelTag.Id(), 160 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 161 }, 162 }}, 163 }) 164 } 165 166 func (s *CAASProvisionerSuite) TestOperatorProvisioningInfo(c *gc.C) { 167 s.st.operatorRepo = "somerepo" 168 s.st.app = &mockApplication{ 169 charm: &mockCharm{meta: &charm.Meta{}}, 170 } 171 result, err := s.api.OperatorProvisioningInfo(params.Entities{Entities: []params.Entity{{"application-gitlab"}}}) 172 c.Assert(err, jc.ErrorIsNil) 173 c.Assert(result, jc.DeepEquals, params.OperatorProvisioningInfoResults{ 174 Results: []params.OperatorProvisioningInfo{{ 175 ImageDetails: params.DockerImageInfo{ 176 RegistryPath: s.st.operatorRepo + "/jujud-operator:" + "2.6-beta3.666", 177 Repository: s.st.operatorRepo, 178 }, 179 BaseImageDetails: params.DockerImageInfo{ 180 RegistryPath: s.st.operatorRepo + "/charm-base:ubuntu-20.04", 181 Repository: s.st.operatorRepo, 182 }, 183 Version: version.MustParse("2.6-beta3.666"), 184 APIAddresses: []string{"10.0.0.1:1"}, 185 Tags: map[string]string{ 186 "juju-model-uuid": coretesting.ModelTag.Id(), 187 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 188 CharmStorage: ¶ms.KubernetesFilesystemParams{ 189 StorageName: "charm", 190 Size: uint64(1024), 191 Provider: "kubernetes", 192 Attributes: map[string]interface{}{ 193 "storage-class": "k8s-storage", 194 "foo": "bar", 195 }, 196 Tags: map[string]string{ 197 "juju-model-uuid": coretesting.ModelTag.Id(), 198 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 199 }, 200 }}, 201 }) 202 } 203 204 func (s *CAASProvisionerSuite) TestOperatorProvisioningInfoNoStorage(c *gc.C) { 205 s.st.operatorRepo = "somerepo" 206 minVers := version.MustParse("2.8.0") 207 s.st.app = &mockApplication{ 208 charm: &mockCharm{meta: &charm.Meta{MinJujuVersion: minVers}}, 209 } 210 result, err := s.api.OperatorProvisioningInfo(params.Entities{Entities: []params.Entity{{"application-gitlab"}}}) 211 c.Assert(err, jc.ErrorIsNil) 212 c.Assert(result, jc.DeepEquals, params.OperatorProvisioningInfoResults{ 213 Results: []params.OperatorProvisioningInfo{{ 214 ImageDetails: params.DockerImageInfo{ 215 RegistryPath: s.st.operatorRepo + "/jujud-operator:" + "2.6-beta3.666", 216 Repository: s.st.operatorRepo, 217 }, 218 BaseImageDetails: params.DockerImageInfo{ 219 RegistryPath: s.st.operatorRepo + "/charm-base:ubuntu-20.04", 220 Repository: s.st.operatorRepo, 221 }, 222 Version: version.MustParse("2.6-beta3.666"), 223 APIAddresses: []string{"10.0.0.1:1"}, 224 Tags: map[string]string{ 225 "juju-model-uuid": coretesting.ModelTag.Id(), 226 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 227 }}, 228 }) 229 } 230 231 func (s *CAASProvisionerSuite) TestOperatorProvisioningInfoSidecarNoStorage(c *gc.C) { 232 s.st.operatorRepo = "somerepo" 233 s.st.app = &mockApplication{ 234 charm: &mockCharm{ 235 meta: &charm.Meta{}, 236 manifest: &charm.Manifest{Bases: []charm.Base{{}}}}, 237 } 238 result, err := s.api.OperatorProvisioningInfo(params.Entities{Entities: []params.Entity{{"application-gitlab"}}}) 239 c.Assert(err, jc.ErrorIsNil) 240 c.Assert(result, jc.DeepEquals, params.OperatorProvisioningInfoResults{ 241 Results: []params.OperatorProvisioningInfo{{ 242 ImageDetails: params.DockerImageInfo{ 243 RegistryPath: s.st.operatorRepo + "/jujud-operator:" + "2.6-beta3.666", 244 Repository: s.st.operatorRepo, 245 }, 246 BaseImageDetails: params.DockerImageInfo{ 247 RegistryPath: s.st.operatorRepo + "/charm-base:ubuntu-20.04", 248 Repository: s.st.operatorRepo, 249 }, 250 Version: version.MustParse("2.6-beta3.666"), 251 APIAddresses: []string{"10.0.0.1:1"}, 252 Tags: map[string]string{ 253 "juju-model-uuid": coretesting.ModelTag.Id(), 254 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 255 }}, 256 }) 257 } 258 259 func (s *CAASProvisionerSuite) TestOperatorProvisioningInfoNoStoragePool(c *gc.C) { 260 s.storagePoolManager.SetErrors(errors.NotFoundf("pool")) 261 s.st.operatorRepo = "somerepo" 262 minVers := version.MustParse("2.7.0") 263 s.st.app = &mockApplication{ 264 charm: &mockCharm{meta: &charm.Meta{MinJujuVersion: minVers}}, 265 } 266 result, err := s.api.OperatorProvisioningInfo(params.Entities{Entities: []params.Entity{{"application-gitlab"}}}) 267 c.Assert(err, jc.ErrorIsNil) 268 c.Assert(result, jc.DeepEquals, params.OperatorProvisioningInfoResults{ 269 Results: []params.OperatorProvisioningInfo{{ 270 ImageDetails: params.DockerImageInfo{ 271 RegistryPath: s.st.operatorRepo + "/jujud-operator:" + "2.6-beta3.666", 272 Repository: s.st.operatorRepo, 273 }, 274 BaseImageDetails: params.DockerImageInfo{ 275 RegistryPath: s.st.operatorRepo + "/charm-base:ubuntu-20.04", 276 Repository: s.st.operatorRepo, 277 }, 278 Version: version.MustParse("2.6-beta3.666"), 279 APIAddresses: []string{"10.0.0.1:1"}, 280 Tags: map[string]string{ 281 "juju-model-uuid": coretesting.ModelTag.Id(), 282 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 283 CharmStorage: ¶ms.KubernetesFilesystemParams{ 284 StorageName: "charm", 285 Size: uint64(1024), 286 Provider: "kubernetes", 287 Attributes: map[string]interface{}{ 288 "storage-class": "k8s-storage", 289 }, 290 Tags: map[string]string{ 291 "juju-model-uuid": coretesting.ModelTag.Id(), 292 "juju-controller-uuid": coretesting.ControllerTag.Id()}, 293 }, 294 }}, 295 }) 296 } 297 298 func (s *CAASProvisionerSuite) TestAddresses(c *gc.C) { 299 _, err := s.api.APIAddresses() 300 c.Assert(err, jc.ErrorIsNil) 301 s.st.CheckCallNames(c, "APIHostPortsForAgents") 302 } 303 304 func (s *CAASProvisionerSuite) TestIssueOperatorCertificate(c *gc.C) { 305 res, err := s.api.IssueOperatorCertificate(params.Entities{ 306 Entities: []params.Entity{{Tag: "application-appname"}}, 307 }) 308 c.Assert(err, jc.ErrorIsNil) 309 s.st.CheckCallNames(c, "StateServingInfo") 310 c.Assert(res.Results, gc.HasLen, 1) 311 certInfo := res.Results[0] 312 c.Assert(certInfo.Error, gc.IsNil) 313 314 certs, signers, err := pki.UnmarshalPemData(append([]byte(certInfo.Cert), 315 []byte(certInfo.PrivateKey)...)) 316 c.Assert(err, jc.ErrorIsNil) 317 c.Assert(len(signers), gc.Equals, 1) 318 c.Assert(len(certs), gc.Equals, 2) 319 320 roots := x509.NewCertPool() 321 ok := roots.AppendCertsFromPEM([]byte(certInfo.CACert)) 322 c.Assert(ok, jc.IsTrue) 323 _, err = certs[0].Verify(x509.VerifyOptions{ 324 DNSName: "appname", 325 Roots: roots, 326 }) 327 c.Assert(err, jc.ErrorIsNil) 328 }