github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 jujucontroller "github.com/juju/juju/controller" 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) ControllerConfig() (jujucontroller.Config, error) { 94 return map[string]interface{}{ 95 jujucontroller.CACertKey: coretesting.CACert, 96 }, nil 97 } 98 99 type mockAPIHostGetter struct{} 100 101 func (g *mockAPIHostGetter) APIHostPorts() ([][]network.HostPort, error) { 102 return [][]network.HostPort{ 103 { 104 {Address: network.Address{Value: "192.168.1.1", Scope: network.ScopeCloudLocal}, Port: 17070}, 105 {Address: network.Address{Value: "10.1.1.1", Scope: network.ScopeMachineLocal}, Port: 17070}, 106 }, 107 }, nil 108 } 109 110 func (s *CertUpdaterSuite) TestStartStop(c *gc.C) { 111 var initialAddresses []string 112 setter := func(info params.StateServingInfo, dying <-chan struct{}) error { 113 // Only care about first time called. 114 if len(initialAddresses) > 0 { 115 return nil 116 } 117 srvCert, err := cert.ParseCert(info.Cert) 118 c.Assert(err, jc.ErrorIsNil) 119 initialAddresses = make([]string, len(srvCert.IPAddresses)) 120 for i, ip := range srvCert.IPAddresses { 121 initialAddresses[i] = ip.String() 122 } 123 return nil 124 } 125 changes := make(chan struct{}) 126 worker := certupdater.NewCertificateUpdater( 127 &mockMachine{changes}, s, &mockConfigGetter{}, &mockAPIHostGetter{}, setter, 128 ) 129 worker.Kill() 130 c.Assert(worker.Wait(), gc.IsNil) 131 // Initial cert addresses initialised to cloud local ones. 132 c.Assert(initialAddresses, jc.DeepEquals, []string{"192.168.1.1"}) 133 } 134 135 func (s *CertUpdaterSuite) TestAddressChange(c *gc.C) { 136 var srvCert *x509.Certificate 137 updated := make(chan struct{}) 138 setter := func(info params.StateServingInfo, dying <-chan struct{}) error { 139 s.stateServingInfo = info 140 var err error 141 srvCert, err = cert.ParseCert(info.Cert) 142 c.Assert(err, jc.ErrorIsNil) 143 sanIPs := make([]string, len(srvCert.IPAddresses)) 144 for i, ip := range srvCert.IPAddresses { 145 sanIPs[i] = ip.String() 146 } 147 sanIPsSet := set.NewStrings(sanIPs...) 148 if sanIPsSet.Size() == 2 && sanIPsSet.Contains("0.1.2.3") && sanIPsSet.Contains("192.168.1.1") { 149 close(updated) 150 } 151 return nil 152 } 153 changes := make(chan struct{}) 154 worker := certupdater.NewCertificateUpdater( 155 &mockMachine{changes}, s, &mockConfigGetter{}, &mockAPIHostGetter{}, setter, 156 ) 157 defer func() { c.Assert(worker.Wait(), gc.IsNil) }() 158 defer worker.Kill() 159 160 changes <- struct{}{} 161 // Certificate should be updated with the address value. 162 select { 163 case <-updated: 164 case <-time.After(coretesting.LongWait): 165 c.Fatalf("timed out waiting for certificate to be updated") 166 } 167 168 // The server certificates must report "juju-apiserver" as a DNS 169 // name for backwards-compatibility with API clients. They must 170 // also report "juju-mongodb" because these certicates are also 171 // used for serving MongoDB connections. 172 c.Assert(srvCert.DNSNames, jc.SameContents, 173 []string{"localhost", "juju-apiserver", "juju-mongodb", "anything"}) 174 } 175 176 type mockStateServingGetterNoCAKey struct{} 177 178 func (g *mockStateServingGetterNoCAKey) StateServingInfo() (params.StateServingInfo, bool) { 179 return params.StateServingInfo{ 180 Cert: coretesting.ServerCert, 181 PrivateKey: coretesting.ServerKey, 182 StatePort: 123, 183 APIPort: 456, 184 }, true 185 186 } 187 188 func (s *CertUpdaterSuite) TestAddressChangeNoCAKey(c *gc.C) { 189 updated := make(chan struct{}) 190 setter := func(info params.StateServingInfo, dying <-chan struct{}) error { 191 close(updated) 192 return nil 193 } 194 changes := make(chan struct{}) 195 worker := certupdater.NewCertificateUpdater( 196 &mockMachine{changes}, &mockStateServingGetterNoCAKey{}, &mockConfigGetter{}, &mockAPIHostGetter{}, setter, 197 ) 198 defer func() { c.Assert(worker.Wait(), gc.IsNil) }() 199 defer worker.Kill() 200 201 changes <- struct{}{} 202 // Certificate should not be updated with the address value. 203 select { 204 case <-time.After(coretesting.ShortWait): 205 case <-updated: 206 c.Fatalf("set state serving info unexpectedly called") 207 } 208 }