github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/common/tools_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/params" 16 apiservertesting "github.com/juju/juju/apiserver/testing" 17 "github.com/juju/juju/environs" 18 "github.com/juju/juju/juju/arch" 19 "github.com/juju/juju/juju/testing" 20 "github.com/juju/juju/network" 21 "github.com/juju/juju/state" 22 "github.com/juju/juju/state/toolstorage" 23 coretools "github.com/juju/juju/tools" 24 "github.com/juju/juju/version" 25 ) 26 27 type toolsSuite struct { 28 testing.JujuConnSuite 29 machine0 *state.Machine 30 } 31 32 var _ = gc.Suite(&toolsSuite{}) 33 34 func (s *toolsSuite) SetUpTest(c *gc.C) { 35 s.JujuConnSuite.SetUpTest(c) 36 var err error 37 s.machine0, err = s.State.AddMachine("series", state.JobHostUnits) 38 c.Assert(err, jc.ErrorIsNil) 39 s.AddDefaultToolsToState(c) 40 } 41 42 func (s *toolsSuite) TestTools(c *gc.C) { 43 getCanRead := func() (common.AuthFunc, error) { 44 return func(tag names.Tag) bool { 45 return tag == names.NewMachineTag("0") || tag == names.NewMachineTag("42") 46 }, nil 47 } 48 tg := common.NewToolsGetter(s.State, s.State, s.State, sprintfURLGetter("tools:%s"), getCanRead) 49 c.Assert(tg, gc.NotNil) 50 51 err := s.machine0.SetAgentVersion(version.Current) 52 c.Assert(err, jc.ErrorIsNil) 53 54 args := params.Entities{ 55 Entities: []params.Entity{ 56 {Tag: "machine-0"}, 57 {Tag: "machine-1"}, 58 {Tag: "machine-42"}, 59 }} 60 result, err := tg.Tools(args) 61 c.Assert(err, jc.ErrorIsNil) 62 c.Assert(result.Results, gc.HasLen, 3) 63 c.Assert(result.Results[0].Error, gc.IsNil) 64 c.Assert(result.Results[0].Tools, gc.NotNil) 65 c.Assert(result.Results[0].Tools.Version, gc.DeepEquals, version.Current) 66 c.Assert(result.Results[0].Tools.URL, gc.Equals, "tools:"+version.Current.String()) 67 c.Assert(result.Results[0].DisableSSLHostnameVerification, jc.IsTrue) 68 c.Assert(result.Results[1].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 69 c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.NotFoundError("machine 42")) 70 } 71 72 func (s *toolsSuite) TestToolsError(c *gc.C) { 73 getCanRead := func() (common.AuthFunc, error) { 74 return nil, fmt.Errorf("splat") 75 } 76 tg := common.NewToolsGetter(s.State, s.State, s.State, sprintfURLGetter("%s"), getCanRead) 77 args := params.Entities{ 78 Entities: []params.Entity{{Tag: "machine-42"}}, 79 } 80 result, err := tg.Tools(args) 81 c.Assert(err, gc.ErrorMatches, "splat") 82 c.Assert(result.Results, gc.HasLen, 1) 83 } 84 85 func (s *toolsSuite) TestSetTools(c *gc.C) { 86 getCanWrite := func() (common.AuthFunc, error) { 87 return func(tag names.Tag) bool { 88 return tag == names.NewMachineTag("0") || tag == names.NewMachineTag("42") 89 }, nil 90 } 91 ts := common.NewToolsSetter(s.State, getCanWrite) 92 c.Assert(ts, gc.NotNil) 93 94 err := s.machine0.SetAgentVersion(version.Current) 95 c.Assert(err, jc.ErrorIsNil) 96 97 args := params.EntitiesVersion{ 98 AgentTools: []params.EntityVersion{{ 99 Tag: "machine-0", 100 Tools: ¶ms.Version{ 101 Version: version.Current, 102 }, 103 }, { 104 Tag: "machine-1", 105 Tools: ¶ms.Version{ 106 Version: version.Current, 107 }, 108 }, { 109 Tag: "machine-42", 110 Tools: ¶ms.Version{ 111 Version: version.Current, 112 }, 113 }}, 114 } 115 result, err := ts.SetTools(args) 116 c.Assert(err, jc.ErrorIsNil) 117 c.Assert(result.Results, gc.HasLen, 3) 118 c.Assert(result.Results[0].Error, gc.IsNil) 119 agentTools, err := s.machine0.AgentTools() 120 c.Assert(err, jc.ErrorIsNil) 121 c.Assert(agentTools.Version, gc.DeepEquals, version.Current) 122 c.Assert(result.Results[1].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 123 c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.NotFoundError("machine 42")) 124 } 125 126 func (s *toolsSuite) TestToolsSetError(c *gc.C) { 127 getCanWrite := func() (common.AuthFunc, error) { 128 return nil, fmt.Errorf("splat") 129 } 130 ts := common.NewToolsSetter(s.State, getCanWrite) 131 args := params.EntitiesVersion{ 132 AgentTools: []params.EntityVersion{{ 133 Tag: "machine-42", 134 Tools: ¶ms.Version{ 135 Version: version.Current, 136 }, 137 }}, 138 } 139 result, err := ts.SetTools(args) 140 c.Assert(err, gc.ErrorMatches, "splat") 141 c.Assert(result.Results, gc.HasLen, 1) 142 } 143 144 func (s *toolsSuite) TestFindTools(c *gc.C) { 145 envtoolsList := coretools.List{ 146 &coretools.Tools{ 147 Version: version.MustParseBinary("123.456.0-win81-alpha"), 148 Size: 2048, 149 SHA256: "badf00d", 150 }, 151 &coretools.Tools{ 152 Version: version.MustParseBinary("123.456.1-win81-alpha"), 153 }, 154 } 155 storageMetadata := []toolstorage.Metadata{{ 156 Version: version.MustParseBinary("123.456.0-win81-alpha"), 157 Size: 1024, 158 SHA256: "feedface", 159 }} 160 161 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (coretools.List, error) { 162 c.Assert(major, gc.Equals, 123) 163 c.Assert(minor, gc.Equals, 456) 164 c.Assert(stream, gc.Equals, "released") 165 c.Assert(filter.Series, gc.Equals, "win81") 166 c.Assert(filter.Arch, gc.Equals, "alpha") 167 return envtoolsList, nil 168 }) 169 toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{metadata: storageMetadata}, sprintfURLGetter("tools:%s")) 170 result, err := toolsFinder.FindTools(params.FindToolsParams{ 171 MajorVersion: 123, 172 MinorVersion: 456, 173 Series: "win81", 174 Arch: "alpha", 175 }) 176 c.Assert(err, jc.ErrorIsNil) 177 c.Assert(result.Error, gc.IsNil) 178 c.Assert(result.List, gc.DeepEquals, coretools.List{ 179 &coretools.Tools{ 180 Version: storageMetadata[0].Version, 181 Size: storageMetadata[0].Size, 182 SHA256: storageMetadata[0].SHA256, 183 URL: "tools:" + storageMetadata[0].Version.String(), 184 }, 185 envtoolsList[1], 186 }) 187 } 188 189 func (s *toolsSuite) TestFindToolsNotFound(c *gc.C) { 190 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) { 191 return nil, errors.NotFoundf("tools") 192 }) 193 toolsFinder := common.NewToolsFinder(s.State, s.State, sprintfURLGetter("%s")) 194 result, err := toolsFinder.FindTools(params.FindToolsParams{}) 195 c.Assert(err, jc.ErrorIsNil) 196 c.Assert(result.Error, jc.Satisfies, params.IsCodeNotFound) 197 } 198 199 func (s *toolsSuite) TestFindToolsExactInStorage(c *gc.C) { 200 mockToolsStorage := &mockToolsStorage{ 201 metadata: []toolstorage.Metadata{ 202 {Version: version.MustParseBinary("1.22-beta1-trusty-amd64")}, 203 {Version: version.MustParseBinary("1.22.0-trusty-amd64")}, 204 }, 205 } 206 207 s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 }) 208 s.PatchValue(&version.Current, version.MustParseBinary("1.22-beta1-trusty-amd64")) 209 s.testFindToolsExact(c, mockToolsStorage, true, true) 210 s.PatchValue(&version.Current, version.MustParseBinary("1.22.0-trusty-amd64")) 211 s.testFindToolsExact(c, mockToolsStorage, true, false) 212 } 213 214 func (s *toolsSuite) TestFindToolsExactNotInStorage(c *gc.C) { 215 mockToolsStorage := &mockToolsStorage{} 216 s.PatchValue(&version.Current.Number, version.MustParse("1.22-beta1")) 217 s.testFindToolsExact(c, mockToolsStorage, false, true) 218 s.PatchValue(&version.Current.Number, version.MustParse("1.22.0")) 219 s.testFindToolsExact(c, mockToolsStorage, false, false) 220 } 221 222 func (s *toolsSuite) testFindToolsExact(c *gc.C, t common.ToolsStorageGetter, inStorage bool, develVersion bool) { 223 var called bool 224 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) { 225 called = true 226 c.Assert(filter.Number, gc.Equals, version.Current.Number) 227 c.Assert(filter.Series, gc.Equals, version.Current.Series) 228 c.Assert(filter.Arch, gc.Equals, arch.HostArch()) 229 if develVersion { 230 c.Assert(stream, gc.Equals, "devel") 231 } else { 232 c.Assert(stream, gc.Equals, "released") 233 } 234 return nil, errors.NotFoundf("tools") 235 }) 236 toolsFinder := common.NewToolsFinder(s.State, t, sprintfURLGetter("tools:%s")) 237 result, err := toolsFinder.FindTools(params.FindToolsParams{ 238 Number: version.Current.Number, 239 MajorVersion: -1, 240 MinorVersion: -1, 241 Series: version.Current.Series, 242 Arch: arch.HostArch(), 243 }) 244 c.Assert(err, jc.ErrorIsNil) 245 if inStorage { 246 c.Assert(result.Error, gc.IsNil) 247 c.Assert(called, jc.IsFalse) 248 } else { 249 c.Assert(result.Error, gc.ErrorMatches, "tools not found") 250 c.Assert(called, jc.IsTrue) 251 } 252 } 253 254 func (s *toolsSuite) TestFindToolsToolsStorageError(c *gc.C) { 255 var called bool 256 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, stream string, filter coretools.Filter) (list coretools.List, err error) { 257 called = true 258 return nil, errors.NotFoundf("tools") 259 }) 260 toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{ 261 err: errors.New("AllMetadata failed"), 262 }, sprintfURLGetter("tools:%s")) 263 result, err := toolsFinder.FindTools(params.FindToolsParams{ 264 MajorVersion: 1, 265 MinorVersion: -1, 266 }) 267 c.Assert(err, jc.ErrorIsNil) 268 // ToolsStorage errors always cause FindTools to bail. Only 269 // if AllMetadata succeeds but returns nothing that matches 270 // do we continue on to searching simplestreams. 271 c.Assert(result.Error, gc.ErrorMatches, "AllMetadata failed") 272 c.Assert(called, jc.IsFalse) 273 } 274 275 func (s *toolsSuite) TestToolsURLGetterNoAPIHostPorts(c *gc.C) { 276 g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{}) 277 _, err := g.ToolsURL(version.Current) 278 c.Assert(err, gc.ErrorMatches, "no API host ports") 279 } 280 281 func (s *toolsSuite) TestToolsURLGetterAPIHostPortsError(c *gc.C) { 282 g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{err: errors.New("oh noes")}) 283 _, err := g.ToolsURL(version.Current) 284 c.Assert(err, gc.ErrorMatches, "oh noes") 285 } 286 287 func (s *toolsSuite) TestToolsURLGetter(c *gc.C) { 288 g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{ 289 hostPorts: [][]network.HostPort{ 290 network.NewHostPorts(1234, "0.1.2.3"), 291 }, 292 }) 293 url, err := g.ToolsURL(version.Current) 294 c.Assert(err, jc.ErrorIsNil) 295 c.Assert(url, gc.Equals, "https://0.1.2.3:1234/environment/my-uuid/tools/"+version.Current.String()) 296 } 297 298 type sprintfURLGetter string 299 300 func (s sprintfURLGetter) ToolsURL(v version.Binary) (string, error) { 301 return fmt.Sprintf(string(s), v), nil 302 } 303 304 type mockAPIHostPortsGetter struct { 305 hostPorts [][]network.HostPort 306 err error 307 } 308 309 func (g mockAPIHostPortsGetter) APIHostPorts() ([][]network.HostPort, error) { 310 return g.hostPorts, g.err 311 } 312 313 type mockToolsStorage struct { 314 toolstorage.Storage 315 metadata []toolstorage.Metadata 316 err error 317 } 318 319 func (s *mockToolsStorage) ToolsStorage() (toolstorage.StorageCloser, error) { 320 return s, nil 321 } 322 323 func (s *mockToolsStorage) Close() error { 324 return nil 325 } 326 327 func (s *mockToolsStorage) AllMetadata() ([]toolstorage.Metadata, error) { 328 return s.metadata, s.err 329 }