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