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  }