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  }