github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/environs/bootstrap/config_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package bootstrap_test 5 6 import ( 7 "os" 8 "time" 9 10 gitjujutesting "github.com/juju/testing" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/environs/bootstrap" 15 "github.com/juju/juju/juju/osenv" 16 "github.com/juju/juju/testing" 17 ) 18 19 type ConfigSuite struct { 20 testing.FakeJujuXDGDataHomeSuite 21 } 22 23 var _ = gc.Suite(&ConfigSuite{}) 24 25 func (*ConfigSuite) TestDefaultConfig(c *gc.C) { 26 cfg, err := bootstrap.NewConfig(nil) 27 c.Assert(err, jc.ErrorIsNil) 28 29 // These three things are generated. 30 c.Assert(cfg.AdminSecret, gc.Not(gc.HasLen), 0) 31 c.Assert(cfg.CACert, gc.Not(gc.HasLen), 0) 32 c.Assert(cfg.CAPrivateKey, gc.Not(gc.HasLen), 0) 33 34 c.Assert(cfg.BootstrapTimeout, gc.Equals, time.Second*1200) 35 c.Assert(cfg.BootstrapRetryDelay, gc.Equals, time.Second*5) 36 c.Assert(cfg.BootstrapAddressesDelay, gc.Equals, time.Second*10) 37 } 38 39 func (*ConfigSuite) TestConfigValuesSpecified(c *gc.C) { 40 for _, serviceType := range []string{"external", "loadbalancer"} { 41 externalIps := []string{"10.0.0.1", "10.0.0.2"} 42 if serviceType == "loadbalancer" { 43 externalIps = externalIps[:1] 44 } 45 cfg, err := bootstrap.NewConfig(map[string]interface{}{ 46 "admin-secret": "sekrit", 47 "ca-cert": testing.CACert, 48 "ca-private-key": testing.CAKey, 49 "bootstrap-timeout": 1, 50 "bootstrap-retry-delay": 2, 51 "bootstrap-addresses-delay": 3, 52 "controller-service-type": serviceType, 53 "controller-external-name": "externalName", 54 "controller-external-ips": externalIps, 55 }) 56 c.Assert(err, jc.ErrorIsNil) 57 58 c.Assert(cfg, jc.DeepEquals, bootstrap.Config{ 59 AdminSecret: "sekrit", 60 CACert: testing.CACert, 61 CAPrivateKey: testing.CAKey, 62 BootstrapTimeout: time.Second * 1, 63 BootstrapRetryDelay: time.Second * 2, 64 BootstrapAddressesDelay: time.Second * 3, 65 ControllerServiceType: serviceType, 66 ControllerExternalName: "externalName", 67 ControllerExternalIPs: externalIps, 68 }) 69 } 70 } 71 72 func (s *ConfigSuite) addFiles(c *gc.C, files ...gitjujutesting.TestFile) { 73 for _, f := range files { 74 err := os.WriteFile(osenv.JujuXDGDataHomePath(f.Name), []byte(f.Data), 0666) 75 c.Assert(err, gc.IsNil) 76 } 77 } 78 79 func (s *ConfigSuite) TestDefaultConfigReadsDefaultCACertKeyFiles(c *gc.C) { 80 s.addFiles(c, []gitjujutesting.TestFile{ 81 {"ca-cert.pem", testing.CACert}, 82 {"ca-private-key.pem", testing.CAKey}, 83 }...) 84 85 cfg, err := bootstrap.NewConfig(nil) 86 c.Assert(err, jc.ErrorIsNil) 87 88 c.Assert(cfg.CACert, gc.Equals, testing.CACert) 89 c.Assert(cfg.CAPrivateKey, gc.Equals, testing.CAKey) 90 } 91 92 func (s *ConfigSuite) TestConfigReadsCACertKeyFilesFromPaths(c *gc.C) { 93 s.addFiles(c, []gitjujutesting.TestFile{ 94 {"ca-cert-2.pem", testing.OtherCACert}, 95 {"ca-private-key-2.pem", testing.OtherCAKey}, 96 }...) 97 98 cfg, err := bootstrap.NewConfig(map[string]interface{}{ 99 "ca-cert-path": "ca-cert-2.pem", 100 "ca-private-key-path": "ca-private-key-2.pem", 101 }) 102 c.Assert(err, jc.ErrorIsNil) 103 104 c.Assert(cfg.CACert, gc.Equals, testing.OtherCACert) 105 c.Assert(cfg.CAPrivateKey, gc.Equals, testing.OtherCAKey) 106 } 107 108 func (s *ConfigSuite) TestConfigNonExistentPath(c *gc.C) { 109 s.testConfigError(c, map[string]interface{}{ 110 "ca-cert-path": "not/there", 111 }, `reading "ca-cert" from file: "ca-cert" not set, and could not read from "not/there": .*`) 112 } 113 114 func (s *ConfigSuite) TestConfigInvalidCACert(c *gc.C) { 115 s.testConfigError(c, map[string]interface{}{ 116 "ca-cert": invalidCACert, 117 "ca-private-key": testing.CAKey, 118 }, "validating ca-cert and ca-private-key: x509: malformed certificate") 119 } 120 121 func (s *ConfigSuite) TestConfigInvalidCAKey(c *gc.C) { 122 s.testConfigError(c, map[string]interface{}{ 123 "ca-cert": testing.CACert, 124 "ca-private-key": invalidCAKey, 125 }, "validating ca-cert and ca-private-key: (crypto/)?tls: failed to parse private key") 126 } 127 128 func (s *ConfigSuite) TestConfigCACertKeyMismatch(c *gc.C) { 129 s.testConfigError(c, map[string]interface{}{ 130 "ca-cert": testing.CACert, 131 "ca-private-key": testing.OtherCAKey, 132 }, "validating ca-cert and ca-private-key: (crypto/)?tls: private key does not match public key") 133 } 134 135 func (s *ConfigSuite) TestConfigCACertWithEmptyKey(c *gc.C) { 136 s.testConfigError(c, map[string]interface{}{ 137 "ca-cert": testing.CACert, 138 }, "validating ca-cert and ca-private-key: (crypto/)?tls: failed to find any PEM data in key input") 139 } 140 141 func (s *ConfigSuite) TestConfigEmptyCACertWithKey(c *gc.C) { 142 s.testConfigError(c, map[string]interface{}{ 143 "ca-private-key": testing.CAKey, 144 }, "validating ca-cert and ca-private-key: (crypto/)?tls: failed to find any PEM data in certificate input") 145 } 146 147 func (*ConfigSuite) testConfigError(c *gc.C, attrs map[string]interface{}, expect string) { 148 _, err := bootstrap.NewConfig(attrs) 149 c.Assert(err, gc.ErrorMatches, expect) 150 } 151 152 func (*ConfigSuite) TestValidate(c *gc.C) { 153 c.Assert(validConfig().Validate(), jc.ErrorIsNil) 154 } 155 156 func (*ConfigSuite) TestValidateAdminSecret(c *gc.C) { 157 cfg := validConfig() 158 cfg.AdminSecret = "" 159 c.Assert(cfg.Validate(), gc.ErrorMatches, "empty admin-secret not valid") 160 } 161 162 func (*ConfigSuite) TestValidateBootstrapTimeout(c *gc.C) { 163 cfg := validConfig() 164 cfg.BootstrapTimeout = 0 165 c.Assert(cfg.Validate(), gc.ErrorMatches, "bootstrap-timeout of 0s? not valid") 166 } 167 168 func (*ConfigSuite) TestValidateBootstrapRetryDelay(c *gc.C) { 169 cfg := validConfig() 170 cfg.BootstrapRetryDelay = -1 * time.Second 171 c.Assert(cfg.Validate(), gc.ErrorMatches, "bootstrap-retry-delay of -1s not valid") 172 } 173 174 func (*ConfigSuite) TestValidateBootstrapAddressesDelay(c *gc.C) { 175 cfg := validConfig() 176 cfg.BootstrapAddressesDelay = -2 * time.Minute 177 c.Assert(cfg.Validate(), gc.ErrorMatches, "bootstrap-addresses-delay of -2m0s not valid") 178 } 179 180 func (*ConfigSuite) TestValidateExternalIpsAndServiceType(c *gc.C) { 181 cfg := validConfig() 182 cfg.ControllerServiceType = "cluster" 183 c.Assert(cfg.Validate(), gc.ErrorMatches, `external IPs require a service type of "external" or "loadbalancer"`) 184 } 185 186 func (*ConfigSuite) TestValidateExternalIpsAndLoadBalancer(c *gc.C) { 187 cfg := validConfig() 188 cfg.ControllerServiceType = "loadbalancer" 189 c.Assert(cfg.Validate(), gc.ErrorMatches, `only 1 external IP is allowed with service type "loadbalancer"`) 190 } 191 192 func validConfig() bootstrap.Config { 193 return bootstrap.Config{ 194 AdminSecret: "sekrit", 195 CACert: testing.CACert, 196 CAPrivateKey: testing.CAKey, 197 BootstrapTimeout: time.Second * 1, 198 BootstrapRetryDelay: time.Second * 2, 199 BootstrapAddressesDelay: time.Second * 3, 200 ControllerServiceType: "external", 201 ControllerExternalIPs: []string{"10.0.0.1", "10.0.0.2"}, 202 } 203 } 204 205 var invalidCAKey = ` 206 -----BEGIN RSA PRIVATE KEY----- 207 MIIBOgIBAAJAZabKgKInuOxj5vDWLwHHQtK3/45KB+32D15w94Nt83BmuGxo90lw 208 -----END RSA PRIVATE KEY----- 209 `[1:] 210 211 var invalidCACert = ` 212 -----BEGIN CERTIFICATE----- 213 MIIBOgIBAAJAZabKgKInuOxj5vDWLwHHQtK3/45KB+32D15w94Nt83BmuGxo90lw 214 -----END CERTIFICATE----- 215 `[1:]