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