github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/runner/factory_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package runner_test 5 6 import ( 7 "os" 8 "strings" 9 "time" 10 11 "github.com/juju/errors" 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 "github.com/juju/utils" 15 gc "gopkg.in/check.v1" 16 "gopkg.in/juju/charm.v6-unstable/hooks" 17 "gopkg.in/juju/names.v2" 18 19 "github.com/juju/juju/state" 20 "github.com/juju/juju/worker/uniter/hook" 21 "github.com/juju/juju/worker/uniter/runner" 22 "github.com/juju/juju/worker/uniter/runner/context" 23 runnertesting "github.com/juju/juju/worker/uniter/runner/testing" 24 ) 25 26 type FactorySuite struct { 27 ContextSuite 28 } 29 30 var _ = gc.Suite(&FactorySuite{}) 31 32 func (s *FactorySuite) AssertPaths(c *gc.C, rnr runner.Runner) { 33 c.Assert(runner.RunnerPaths(rnr), gc.DeepEquals, s.paths) 34 } 35 36 func (s *FactorySuite) TestNewCommandRunnerNoRelation(c *gc.C) { 37 rnr, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: -1}) 38 c.Assert(err, jc.ErrorIsNil) 39 s.AssertPaths(c, rnr) 40 } 41 42 func (s *FactorySuite) TestNewCommandRunnerRelationIdDoesNotExist(c *gc.C) { 43 for _, value := range []bool{true, false} { 44 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 45 RelationId: 12, ForceRemoteUnit: value, 46 }) 47 c.Check(err, gc.ErrorMatches, `unknown relation id: 12`) 48 } 49 } 50 51 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitInvalid(c *gc.C) { 52 for _, value := range []bool{true, false} { 53 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 54 RelationId: 0, RemoteUnitName: "blah", ForceRemoteUnit: value, 55 }) 56 c.Check(err, gc.ErrorMatches, `invalid remote unit: blah`) 57 } 58 } 59 60 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitInappropriate(c *gc.C) { 61 for _, value := range []bool{true, false} { 62 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 63 RelationId: -1, RemoteUnitName: "blah/123", ForceRemoteUnit: value, 64 }) 65 c.Check(err, gc.ErrorMatches, `remote unit provided without a relation: blah/123`) 66 } 67 } 68 69 func (s *FactorySuite) TestNewCommandRunnerEmptyRelation(c *gc.C) { 70 _, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: 1}) 71 c.Check(err, gc.ErrorMatches, `cannot infer remote unit in empty relation 1`) 72 } 73 74 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitAmbiguous(c *gc.C) { 75 s.membership[1] = []string{"foo/0", "foo/1"} 76 _, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: 1}) 77 c.Check(err, gc.ErrorMatches, `ambiguous remote unit; possibilities are \[foo/0 foo/1\]`) 78 } 79 80 func (s *FactorySuite) TestNewCommandRunnerRemoteUnitMissing(c *gc.C) { 81 s.membership[0] = []string{"foo/0", "foo/1"} 82 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 83 RelationId: 0, RemoteUnitName: "blah/123", 84 }) 85 c.Check(err, gc.ErrorMatches, `unknown remote unit blah/123; possibilities are \[foo/0 foo/1\]`) 86 } 87 88 func (s *FactorySuite) TestNewCommandRunnerForceNoRemoteUnit(c *gc.C) { 89 rnr, err := s.factory.NewCommandRunner(context.CommandInfo{ 90 RelationId: 0, ForceRemoteUnit: true, 91 }) 92 c.Assert(err, jc.ErrorIsNil) 93 s.AssertPaths(c, rnr) 94 } 95 96 func (s *FactorySuite) TestNewCommandRunnerForceRemoteUnitMissing(c *gc.C) { 97 _, err := s.factory.NewCommandRunner(context.CommandInfo{ 98 RelationId: 0, RemoteUnitName: "blah/123", ForceRemoteUnit: true, 99 }) 100 c.Assert(err, gc.IsNil) 101 } 102 103 func (s *FactorySuite) TestNewCommandRunnerInferRemoteUnit(c *gc.C) { 104 s.membership[0] = []string{"foo/2"} 105 rnr, err := s.factory.NewCommandRunner(context.CommandInfo{RelationId: 0}) 106 c.Assert(err, jc.ErrorIsNil) 107 s.AssertPaths(c, rnr) 108 } 109 110 func (s *FactorySuite) TestNewHookRunner(c *gc.C) { 111 rnr, err := s.factory.NewHookRunner(hook.Info{Kind: hooks.ConfigChanged}) 112 c.Assert(err, jc.ErrorIsNil) 113 s.AssertPaths(c, rnr) 114 } 115 116 func (s *FactorySuite) TestNewHookRunnerWithBadHook(c *gc.C) { 117 rnr, err := s.factory.NewHookRunner(hook.Info{}) 118 c.Assert(rnr, gc.IsNil) 119 c.Assert(err, gc.ErrorMatches, `unknown hook kind ""`) 120 } 121 122 func (s *FactorySuite) TestNewHookRunnerWithStorage(c *gc.C) { 123 // We need to set up a unit that has storage metadata defined. 124 ch := s.AddTestingCharm(c, "storage-block") 125 sCons := map[string]state.StorageConstraints{ 126 "data": {Pool: "", Size: 1024, Count: 1}, 127 } 128 service := s.AddTestingServiceWithStorage(c, "storage-block", ch, sCons) 129 s.machine = nil // allocate a new machine 130 unit := s.AddUnit(c, service) 131 132 storageAttachments, err := s.State.UnitStorageAttachments(unit.UnitTag()) 133 c.Assert(err, jc.ErrorIsNil) 134 c.Assert(storageAttachments, gc.HasLen, 1) 135 storageTag := storageAttachments[0].StorageInstance() 136 137 volume, err := s.State.StorageInstanceVolume(storageTag) 138 c.Assert(err, jc.ErrorIsNil) 139 volumeTag := volume.VolumeTag() 140 machineTag := s.machine.MachineTag() 141 142 err = s.State.SetVolumeInfo( 143 volumeTag, state.VolumeInfo{ 144 VolumeId: "vol-123", 145 Size: 456, 146 }, 147 ) 148 c.Assert(err, jc.ErrorIsNil) 149 err = s.State.SetVolumeAttachmentInfo( 150 machineTag, volumeTag, state.VolumeAttachmentInfo{ 151 DeviceName: "sdb", 152 }, 153 ) 154 c.Assert(err, jc.ErrorIsNil) 155 156 password, err := utils.RandomPassword() 157 err = unit.SetPassword(password) 158 c.Assert(err, jc.ErrorIsNil) 159 st := s.OpenAPIAs(c, unit.Tag(), password) 160 uniter, err := st.Uniter() 161 c.Assert(err, jc.ErrorIsNil) 162 163 contextFactory, err := context.NewContextFactory( 164 uniter, 165 unit.Tag().(names.UnitTag), 166 runnertesting.FakeTracker{}, 167 s.getRelationInfos, 168 s.storage, 169 s.paths, 170 testing.NewClock(time.Time{}), 171 ) 172 c.Assert(err, jc.ErrorIsNil) 173 factory, err := runner.NewFactory( 174 uniter, 175 s.paths, 176 contextFactory, 177 ) 178 c.Assert(err, jc.ErrorIsNil) 179 180 rnr, err := factory.NewHookRunner(hook.Info{ 181 Kind: hooks.StorageAttached, 182 StorageId: "data/0", 183 }) 184 c.Assert(err, jc.ErrorIsNil) 185 s.AssertPaths(c, rnr) 186 ctx := rnr.Context() 187 c.Assert(ctx.UnitName(), gc.Equals, "storage-block/0") 188 } 189 190 func (s *FactorySuite) TestNewHookRunnerWithRelation(c *gc.C) { 191 rnr, err := s.factory.NewHookRunner(hook.Info{ 192 Kind: hooks.RelationBroken, 193 RelationId: 1, 194 }) 195 c.Assert(err, jc.ErrorIsNil) 196 s.AssertPaths(c, rnr) 197 } 198 199 func (s *FactorySuite) TestNewHookRunnerWithBadRelation(c *gc.C) { 200 rnr, err := s.factory.NewHookRunner(hook.Info{ 201 Kind: hooks.RelationBroken, 202 RelationId: 12345, 203 }) 204 c.Assert(rnr, gc.IsNil) 205 c.Assert(err, gc.ErrorMatches, `unknown relation id: 12345`) 206 } 207 208 func (s *FactorySuite) TestNewActionRunnerGood(c *gc.C) { 209 s.SetCharm(c, "dummy") 210 for i, test := range []struct { 211 actionName string 212 payload map[string]interface{} 213 }{ 214 { 215 actionName: "snapshot", 216 payload: map[string]interface{}{ 217 "outfile": "/some/file.bz2", 218 }, 219 }, 220 { 221 // juju-run should work as a predefined action even if 222 // it's not part of the charm 223 actionName: "juju-run", 224 payload: map[string]interface{}{ 225 "command": "foo", 226 "timeout": 0.0, 227 }, 228 }, 229 } { 230 c.Logf("test %d", i) 231 action, err := s.State.EnqueueAction(s.unit.Tag(), test.actionName, test.payload) 232 c.Assert(err, jc.ErrorIsNil) 233 rnr, err := s.factory.NewActionRunner(action.Id()) 234 c.Assert(err, jc.ErrorIsNil) 235 s.AssertPaths(c, rnr) 236 ctx := rnr.Context() 237 data, err := ctx.ActionData() 238 c.Assert(err, jc.ErrorIsNil) 239 c.Assert(data, jc.DeepEquals, &context.ActionData{ 240 Name: test.actionName, 241 Tag: action.ActionTag(), 242 Params: test.payload, 243 ResultsMap: map[string]interface{}{}, 244 }) 245 vars, err := ctx.HookVars(s.paths) 246 c.Assert(err, jc.ErrorIsNil) 247 c.Assert(len(vars) > 0, jc.IsTrue, gc.Commentf("expected HookVars but found none")) 248 combined := strings.Join(vars, "|") 249 c.Assert(combined, gc.Matches, `(^|.*\|)JUJU_ACTION_NAME=`+test.actionName+`(\|.*|$)`) 250 c.Assert(combined, gc.Matches, `(^|.*\|)JUJU_ACTION_UUID=`+action.Id()+`(\|.*|$)`) 251 c.Assert(combined, gc.Matches, `(^|.*\|)JUJU_ACTION_TAG=`+action.Tag().String()+`(\|.*|$)`) 252 } 253 } 254 255 func (s *FactorySuite) TestNewActionRunnerBadCharm(c *gc.C) { 256 rnr, err := s.factory.NewActionRunner("irrelevant") 257 c.Assert(rnr, gc.IsNil) 258 c.Assert(errors.Cause(err), jc.Satisfies, os.IsNotExist) 259 c.Assert(err, gc.Not(jc.Satisfies), runner.IsBadActionError) 260 } 261 262 func (s *FactorySuite) TestNewActionRunnerBadName(c *gc.C) { 263 s.SetCharm(c, "dummy") 264 action, err := s.State.EnqueueAction(s.unit.Tag(), "no-such-action", nil) 265 c.Assert(err, jc.ErrorIsNil) // this will fail when using AddAction on unit 266 rnr, err := s.factory.NewActionRunner(action.Id()) 267 c.Check(rnr, gc.IsNil) 268 c.Check(err, gc.ErrorMatches, "cannot run \"no-such-action\" action: not defined") 269 c.Check(err, jc.Satisfies, runner.IsBadActionError) 270 } 271 272 func (s *FactorySuite) TestNewActionRunnerBadParams(c *gc.C) { 273 s.SetCharm(c, "dummy") 274 action, err := s.State.EnqueueAction(s.unit.Tag(), "snapshot", map[string]interface{}{ 275 "outfile": 123, 276 }) 277 c.Assert(err, jc.ErrorIsNil) // this will fail when state is done right 278 rnr, err := s.factory.NewActionRunner(action.Id()) 279 c.Check(rnr, gc.IsNil) 280 c.Check(err, gc.ErrorMatches, "cannot run \"snapshot\" action: .*") 281 c.Check(err, jc.Satisfies, runner.IsBadActionError) 282 } 283 284 func (s *FactorySuite) TestNewActionRunnerMissingAction(c *gc.C) { 285 s.SetCharm(c, "dummy") 286 action, err := s.State.EnqueueAction(s.unit.Tag(), "snapshot", nil) 287 c.Assert(err, jc.ErrorIsNil) 288 _, err = s.unit.CancelAction(action) 289 c.Assert(err, jc.ErrorIsNil) 290 rnr, err := s.factory.NewActionRunner(action.Id()) 291 c.Check(rnr, gc.IsNil) 292 c.Check(err, gc.ErrorMatches, "action no longer available") 293 c.Check(err, gc.Equals, runner.ErrActionNotAvailable) 294 } 295 296 func (s *FactorySuite) TestNewActionRunnerUnauthAction(c *gc.C) { 297 s.SetCharm(c, "dummy") 298 otherUnit, err := s.service.AddUnit() 299 c.Assert(err, jc.ErrorIsNil) 300 action, err := s.State.EnqueueAction(otherUnit.Tag(), "snapshot", nil) 301 c.Assert(err, jc.ErrorIsNil) 302 rnr, err := s.factory.NewActionRunner(action.Id()) 303 c.Check(rnr, gc.IsNil) 304 c.Check(err, gc.ErrorMatches, "action no longer available") 305 c.Check(err, gc.Equals, runner.ErrActionNotAvailable) 306 }