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