github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/certupdater/certupdater_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package certupdater_test 5 6 import ( 7 "crypto/x509" 8 stdtesting "testing" 9 "time" 10 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/utils/set" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/apiserver/params" 16 "github.com/juju/juju/cert" 17 "github.com/juju/juju/environs/config" 18 "github.com/juju/juju/network" 19 "github.com/juju/juju/state" 20 coretesting "github.com/juju/juju/testing" 21 "github.com/juju/juju/worker/certupdater" 22 ) 23 24 func TestPackage(t *stdtesting.T) { 25 gc.TestingT(t) 26 } 27 28 type CertUpdaterSuite struct { 29 coretesting.BaseSuite 30 stateServingInfo params.StateServingInfo 31 } 32 33 var _ = gc.Suite(&CertUpdaterSuite{}) 34 35 func (s *CertUpdaterSuite) SetUpTest(c *gc.C) { 36 s.BaseSuite.SetUpTest(c) 37 38 s.stateServingInfo = params.StateServingInfo{ 39 Cert: coretesting.ServerCert, 40 PrivateKey: coretesting.ServerKey, 41 CAPrivateKey: coretesting.CAKey, 42 StatePort: 123, 43 APIPort: 456, 44 } 45 } 46 47 type mockNotifyWatcher struct { 48 changes <-chan struct{} 49 } 50 51 func (w *mockNotifyWatcher) Changes() <-chan struct{} { 52 return w.changes 53 } 54 55 func (*mockNotifyWatcher) Stop() error { 56 return nil 57 } 58 59 func (*mockNotifyWatcher) Kill() {} 60 61 func (*mockNotifyWatcher) Wait() error { 62 return nil 63 } 64 65 func (*mockNotifyWatcher) Err() error { 66 return nil 67 } 68 69 func newMockNotifyWatcher(changes <-chan struct{}) state.NotifyWatcher { 70 return &mockNotifyWatcher{changes} 71 } 72 73 type mockMachine struct { 74 changes chan struct{} 75 } 76 77 func (m *mockMachine) WatchAddresses() state.NotifyWatcher { 78 return newMockNotifyWatcher(m.changes) 79 } 80 81 func (m *mockMachine) Addresses() (addresses []network.Address) { 82 return []network.Address{{ 83 Value: "0.1.2.3", 84 }} 85 } 86 87 func (s *CertUpdaterSuite) StateServingInfo() (params.StateServingInfo, bool) { 88 return s.stateServingInfo, true 89 } 90 91 type mockConfigGetter struct{} 92 93 func (g *mockConfigGetter) ModelConfig() (*config.Config, error) { 94 return config.New(config.NoDefaults, coretesting.FakeConfig()) 95 96 } 97 98 type mockAPIHostGetter struct{} 99 100 func (g *mockAPIHostGetter) APIHostPorts() ([][]network.HostPort, error) { 101 return [][]network.HostPort{ 102 { 103 {Address: network.Address{Value: "192.168.1.1", Scope: network.ScopeCloudLocal}, Port: 17070}, 104 {Address: network.Address{Value: "10.1.1.1", Scope: network.ScopeMachineLocal}, Port: 17070}, 105 }, 106 }, nil 107 } 108 109 func (s *CertUpdaterSuite) TestStartStop(c *gc.C) { 110 var initialAddresses []string 111 setter := func(info params.StateServingInfo, dying <-chan struct{}) error { 112 // Only care about first time called. 113 if len(initialAddresses) > 0 { 114 return nil 115 } 116 srvCert, err := cert.ParseCert(info.Cert) 117 c.Assert(err, jc.ErrorIsNil) 118 initialAddresses = make([]string, len(srvCert.IPAddresses)) 119 for i, ip := range srvCert.IPAddresses { 120 initialAddresses[i] = ip.String() 121 } 122 return nil 123 } 124 changes := make(chan struct{}) 125 worker := certupdater.NewCertificateUpdater( 126 &mockMachine{changes}, s, &mockConfigGetter{}, &mockAPIHostGetter{}, setter, 127 ) 128 worker.Kill() 129 c.Assert(worker.Wait(), gc.IsNil) 130 // Initial cert addresses initialised to cloud local ones. 131 c.Assert(initialAddresses, jc.DeepEquals, []string{"192.168.1.1"}) 132 } 133 134 func (s *CertUpdaterSuite) TestAddressChange(c *gc.C) { 135 var srvCert *x509.Certificate 136 updated := make(chan struct{}) 137 setter := func(info params.StateServingInfo, dying <-chan struct{}) error { 138 s.stateServingInfo = info 139 var err error 140 srvCert, err = cert.ParseCert(info.Cert) 141 c.Assert(err, jc.ErrorIsNil) 142 sanIPs := make([]string, len(srvCert.IPAddresses)) 143 for i, ip := range srvCert.IPAddresses { 144 sanIPs[i] = ip.String() 145 } 146 sanIPsSet := set.NewStrings(sanIPs...) 147 if sanIPsSet.Size() == 2 && sanIPsSet.Contains("0.1.2.3") && sanIPsSet.Contains("192.168.1.1") { 148 close(updated) 149 } 150 return nil 151 } 152 changes := make(chan struct{}) 153 worker := certupdater.NewCertificateUpdater( 154 &mockMachine{changes}, s, &mockConfigGetter{}, &mockAPIHostGetter{}, setter, 155 ) 156 defer func() { c.Assert(worker.Wait(), gc.IsNil) }() 157 defer worker.Kill() 158 159 changes <- struct{}{} 160 // Certificate should be updated with the address value. 161 select { 162 case <-updated: 163 case <-time.After(coretesting.LongWait): 164 c.Fatalf("timed out waiting for certificate to be updated") 165 } 166 167 // The server certificates must report "juju-apiserver" as a DNS 168 // name for backwards-compatibility with API clients. They must 169 // also report "juju-mongodb" because these certicates are also 170 // used for serving MongoDB connections. 171 c.Assert(srvCert.DNSNames, jc.SameContents, 172 []string{"localhost", "juju-apiserver", "juju-mongodb", "anything"}) 173 } 174 175 type mockStateServingGetterNoCAKey struct{} 176 177 func (g *mockStateServingGetterNoCAKey) StateServingInfo() (params.StateServingInfo, bool) { 178 return params.StateServingInfo{ 179 Cert: coretesting.ServerCert, 180 PrivateKey: coretesting.ServerKey, 181 StatePort: 123, 182 APIPort: 456, 183 }, true 184 185 } 186 187 func (s *CertUpdaterSuite) TestAddressChangeNoCAKey(c *gc.C) { 188 updated := make(chan struct{}) 189 setter := func(info params.StateServingInfo, dying <-chan struct{}) error { 190 close(updated) 191 return nil 192 } 193 changes := make(chan struct{}) 194 worker := certupdater.NewCertificateUpdater( 195 &mockMachine{changes}, &mockStateServingGetterNoCAKey{}, &mockConfigGetter{}, &mockAPIHostGetter{}, setter, 196 ) 197 defer func() { c.Assert(worker.Wait(), gc.IsNil) }() 198 defer worker.Kill() 199 200 changes <- struct{}{} 201 // Certificate should not be updated with the address value. 202 select { 203 case <-time.After(coretesting.ShortWait): 204 case <-updated: 205 c.Fatalf("set state serving info unexpectedly called") 206 } 207 }