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