github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/worker/authenticationworker/worker_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package authenticationworker_test
     5  
     6  import (
     7  	"strings"
     8  	stdtesting "testing"
     9  	"time"
    10  
    11  	"github.com/juju/names"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/agent"
    16  	"github.com/juju/juju/api"
    17  	"github.com/juju/juju/api/keyupdater"
    18  	jujutesting "github.com/juju/juju/juju/testing"
    19  	"github.com/juju/juju/state"
    20  	coretesting "github.com/juju/juju/testing"
    21  	"github.com/juju/juju/utils/ssh"
    22  	sshtesting "github.com/juju/juju/utils/ssh/testing"
    23  	"github.com/juju/juju/worker"
    24  	"github.com/juju/juju/worker/authenticationworker"
    25  )
    26  
    27  // worstCase is used for timeouts when timing out
    28  // will fail the test. Raising this value should
    29  // not affect the overall running time of the tests
    30  // unless they fail.
    31  const worstCase = 5 * time.Second
    32  
    33  func TestAll(t *stdtesting.T) {
    34  	coretesting.MgoTestPackage(t)
    35  }
    36  
    37  var _ = gc.Suite(&workerSuite{})
    38  
    39  type workerSuite struct {
    40  	jujutesting.JujuConnSuite
    41  	stateMachine  *state.Machine
    42  	machine       *state.Machine
    43  	keyupdaterApi *keyupdater.State
    44  
    45  	existingEnvKey string
    46  	existingKeys   []string
    47  }
    48  
    49  func (s *workerSuite) SetUpTest(c *gc.C) {
    50  	s.JujuConnSuite.SetUpTest(c)
    51  	// Default ssh user is currently "ubuntu".
    52  	c.Assert(authenticationworker.SSHUser, gc.Equals, "ubuntu")
    53  	// Set the ssh user to empty (the current user) as required by the test infrastructure.
    54  	s.PatchValue(&authenticationworker.SSHUser, "")
    55  
    56  	// Replace the default dummy key in the test environment with a valid one.
    57  	// This will be added to the ssh authorised keys when the agent starts.
    58  	s.setAuthorisedKeys(c, sshtesting.ValidKeyOne.Key+" firstuser@host")
    59  	// Record the existing key with its prefix for testing later.
    60  	s.existingEnvKey = sshtesting.ValidKeyOne.Key + " Juju:firstuser@host"
    61  
    62  	// Set up an existing key (which is not in the environment) in the ssh authorised_keys file.
    63  	s.existingKeys = []string{sshtesting.ValidKeyTwo.Key + " existinguser@host"}
    64  	err := ssh.AddKeys(authenticationworker.SSHUser, s.existingKeys...)
    65  	c.Assert(err, jc.ErrorIsNil)
    66  
    67  	var apiRoot *api.State
    68  	apiRoot, s.machine = s.OpenAPIAsNewMachine(c)
    69  	c.Assert(apiRoot, gc.NotNil)
    70  	s.keyupdaterApi = apiRoot.KeyUpdater()
    71  	c.Assert(s.keyupdaterApi, gc.NotNil)
    72  }
    73  
    74  func stop(c *gc.C, w worker.Worker) {
    75  	c.Assert(worker.Stop(w), gc.IsNil)
    76  }
    77  
    78  type mockConfig struct {
    79  	agent.Config
    80  	c   *gc.C
    81  	tag names.Tag
    82  }
    83  
    84  func (mock *mockConfig) Tag() names.Tag {
    85  	return mock.tag
    86  }
    87  
    88  func agentConfig(c *gc.C, tag names.MachineTag) *mockConfig {
    89  	return &mockConfig{c: c, tag: tag}
    90  }
    91  
    92  func (s *workerSuite) setAuthorisedKeys(c *gc.C, keys ...string) {
    93  	keyStr := strings.Join(keys, "\n")
    94  	err := s.BackingState.UpdateEnvironConfig(map[string]interface{}{"authorized-keys": keyStr}, nil, nil)
    95  	c.Assert(err, jc.ErrorIsNil)
    96  	s.BackingState.StartSync()
    97  }
    98  
    99  func (s *workerSuite) waitSSHKeys(c *gc.C, expected []string) {
   100  	timeout := time.After(worstCase)
   101  	for {
   102  		select {
   103  		case <-timeout:
   104  			c.Fatalf("timeout while waiting for authoirsed ssh keys to change")
   105  		case <-time.After(coretesting.ShortWait):
   106  			keys, err := ssh.ListKeys(authenticationworker.SSHUser, ssh.FullKeys)
   107  			c.Assert(err, jc.ErrorIsNil)
   108  			keysStr := strings.Join(keys, "\n")
   109  			expectedStr := strings.Join(expected, "\n")
   110  			if expectedStr != keysStr {
   111  				continue
   112  			}
   113  			return
   114  		}
   115  	}
   116  }
   117  
   118  func (s *workerSuite) TestKeyUpdateRetainsExisting(c *gc.C) {
   119  	authWorker := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
   120  	defer stop(c, authWorker)
   121  
   122  	newKey := sshtesting.ValidKeyThree.Key + " user@host"
   123  	s.setAuthorisedKeys(c, newKey)
   124  	newKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:user@host"
   125  	s.waitSSHKeys(c, append(s.existingKeys, newKeyWithCommentPrefix))
   126  }
   127  
   128  func (s *workerSuite) TestNewKeysInJujuAreSavedOnStartup(c *gc.C) {
   129  	newKey := sshtesting.ValidKeyThree.Key + " user@host"
   130  	s.setAuthorisedKeys(c, newKey)
   131  
   132  	authWorker := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
   133  	defer stop(c, authWorker)
   134  
   135  	newKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:user@host"
   136  	s.waitSSHKeys(c, append(s.existingKeys, newKeyWithCommentPrefix))
   137  }
   138  
   139  func (s *workerSuite) TestDeleteKey(c *gc.C) {
   140  	authWorker := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
   141  	defer stop(c, authWorker)
   142  
   143  	// Add another key
   144  	anotherKey := sshtesting.ValidKeyThree.Key + " another@host"
   145  	s.setAuthorisedKeys(c, s.existingEnvKey, anotherKey)
   146  	anotherKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:another@host"
   147  	s.waitSSHKeys(c, append(s.existingKeys, s.existingEnvKey, anotherKeyWithCommentPrefix))
   148  
   149  	// Delete the original key and check anotherKey plus the existing keys remain.
   150  	s.setAuthorisedKeys(c, anotherKey)
   151  	s.waitSSHKeys(c, append(s.existingKeys, anotherKeyWithCommentPrefix))
   152  }
   153  
   154  func (s *workerSuite) TestMultipleChanges(c *gc.C) {
   155  	authWorker := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
   156  	defer stop(c, authWorker)
   157  	s.waitSSHKeys(c, append(s.existingKeys, s.existingEnvKey))
   158  
   159  	// Perform a set to add a key and delete a key.
   160  	// added: key 3
   161  	// deleted: key 1 (existing env key)
   162  	s.setAuthorisedKeys(c, sshtesting.ValidKeyThree.Key+" yetanother@host")
   163  	yetAnotherKeyWithComment := sshtesting.ValidKeyThree.Key + " Juju:yetanother@host"
   164  	s.waitSSHKeys(c, append(s.existingKeys, yetAnotherKeyWithComment))
   165  }
   166  
   167  func (s *workerSuite) TestWorkerRestart(c *gc.C) {
   168  	authWorker := authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
   169  	defer stop(c, authWorker)
   170  	s.waitSSHKeys(c, append(s.existingKeys, s.existingEnvKey))
   171  
   172  	// Stop the worker and delete and add keys from the environment while it is down.
   173  	// added: key 3
   174  	// deleted: key 1 (existing env key)
   175  	stop(c, authWorker)
   176  	s.setAuthorisedKeys(c, sshtesting.ValidKeyThree.Key+" yetanother@host")
   177  
   178  	// Restart the worker and check that the ssh auth keys are as expected.
   179  	authWorker = authenticationworker.NewWorker(s.keyupdaterApi, agentConfig(c, s.machine.Tag().(names.MachineTag)))
   180  	defer stop(c, authWorker)
   181  
   182  	yetAnotherKeyWithCommentPrefix := sshtesting.ValidKeyThree.Key + " Juju:yetanother@host"
   183  	s.waitSSHKeys(c, append(s.existingKeys, yetAnotherKeyWithCommentPrefix))
   184  }