github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/maas/maas_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package maas 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "path/filepath" 11 "strconv" 12 13 "github.com/juju/collections/set" 14 "github.com/juju/errors" 15 "github.com/juju/gomaasapi" 16 "github.com/juju/os/series" 17 jc "github.com/juju/testing/checkers" 18 "github.com/juju/utils" 19 "github.com/juju/utils/arch" 20 gc "gopkg.in/check.v1" 21 22 "github.com/juju/juju/cloud" 23 "github.com/juju/juju/core/instance" 24 "github.com/juju/juju/environs" 25 "github.com/juju/juju/environs/config" 26 "github.com/juju/juju/environs/context" 27 sstesting "github.com/juju/juju/environs/simplestreams/testing" 28 envtesting "github.com/juju/juju/environs/testing" 29 envtools "github.com/juju/juju/environs/tools" 30 "github.com/juju/juju/juju/keys" 31 supportedversion "github.com/juju/juju/juju/version" 32 "github.com/juju/juju/network" 33 coretesting "github.com/juju/juju/testing" 34 jujuversion "github.com/juju/juju/version" 35 ) 36 37 const maas2VersionResponse = `{"version": "unknown", "subversion": "", "capabilities": ["networks-management", "static-ipaddresses", "ipv6-deployment-ubuntu", "devices-management", "storage-deployment-ubuntu", "network-deployment-ubuntu"]}` 38 39 const maas2DomainsResponse = ` 40 [ 41 { 42 "authoritative": "true", 43 "resource_uri": "/MAAS/api/2.0/domains/0/", 44 "name": "maas", 45 "id": 0, 46 "ttl": null, 47 "resource_record_count": 3 48 } 49 ] 50 ` 51 52 type baseProviderSuite struct { 53 coretesting.FakeJujuXDGDataHomeSuite 54 envtesting.ToolsFixture 55 controllerUUID string 56 57 callCtx *context.CloudCallContext 58 invalidCredential bool 59 } 60 61 func (suite *baseProviderSuite) setupFakeTools(c *gc.C) { 62 suite.PatchValue(&keys.JujuPublicKey, sstesting.SignedMetadataPublicKey) 63 storageDir := c.MkDir() 64 toolsDir := filepath.Join(storageDir, "tools") 65 suite.PatchValue(&envtools.DefaultBaseURL, utils.MakeFileURL(toolsDir)) 66 suite.UploadFakeToolsToDirectory(c, storageDir, "released", "released") 67 } 68 69 func (s *baseProviderSuite) SetUpSuite(c *gc.C) { 70 s.FakeJujuXDGDataHomeSuite.SetUpSuite(c) 71 restoreTimeouts := envtesting.PatchAttemptStrategies(&shortAttempt) 72 restoreFinishBootstrap := envtesting.DisableFinishBootstrap() 73 s.AddCleanup(func(*gc.C) { 74 restoreFinishBootstrap() 75 restoreTimeouts() 76 }) 77 } 78 79 func (s *baseProviderSuite) SetUpTest(c *gc.C) { 80 s.FakeJujuXDGDataHomeSuite.SetUpTest(c) 81 s.ToolsFixture.SetUpTest(c) 82 s.PatchValue(&jujuversion.Current, coretesting.FakeVersionNumber) 83 s.PatchValue(&arch.HostArch, func() string { return arch.AMD64 }) 84 s.PatchValue(&series.MustHostSeries, func() string { return supportedversion.SupportedLTS() }) 85 s.callCtx = &context.CloudCallContext{ 86 InvalidateCredentialFunc: func(string) error { 87 s.invalidCredential = true 88 return nil 89 }, 90 } 91 } 92 93 func (s *baseProviderSuite) TearDownTest(c *gc.C) { 94 s.invalidCredential = false 95 s.ToolsFixture.TearDownTest(c) 96 s.FakeJujuXDGDataHomeSuite.TearDownTest(c) 97 } 98 99 func (s *baseProviderSuite) TearDownSuite(c *gc.C) { 100 s.FakeJujuXDGDataHomeSuite.TearDownSuite(c) 101 } 102 103 type providerSuite struct { 104 baseProviderSuite 105 testMAASObject *gomaasapi.TestMAASObject 106 } 107 108 func spaceJSON(space gomaasapi.CreateSpace) *bytes.Buffer { 109 var out bytes.Buffer 110 err := json.NewEncoder(&out).Encode(space) 111 if err != nil { 112 panic(err) 113 } 114 return &out 115 } 116 117 func (s *providerSuite) SetUpSuite(c *gc.C) { 118 s.baseProviderSuite.SetUpSuite(c) 119 s.testMAASObject = gomaasapi.NewTestMAAS("1.0") 120 } 121 122 func (s *providerSuite) SetUpTest(c *gc.C) { 123 s.baseProviderSuite.SetUpTest(c) 124 mockGetController := func(string, string) (gomaasapi.Controller, error) { 125 return nil, gomaasapi.NewUnsupportedVersionError("oops") 126 } 127 s.PatchValue(&GetMAAS2Controller, mockGetController) 128 // Creating a space ensures that the spaces endpoint won't 404. 129 s.testMAASObject.TestServer.NewSpace(spaceJSON(gomaasapi.CreateSpace{Name: "space-0"})) 130 } 131 132 func (s *providerSuite) TearDownTest(c *gc.C) { 133 s.baseProviderSuite.TearDownTest(c) 134 s.testMAASObject.TestServer.Clear() 135 } 136 137 func (s *providerSuite) TearDownSuite(c *gc.C) { 138 s.baseProviderSuite.TearDownSuite(c) 139 s.testMAASObject.Close() 140 } 141 142 var maasEnvAttrs = coretesting.Attrs{ 143 "name": "test-env", 144 "type": "maas", 145 config.ResourceTagsKey: map[string]string{ 146 "claude": "rains", 147 }, 148 } 149 150 func (suite *providerSuite) makeEnvironWithURL(url string, getCapabilities MaasCapabilities) (*maasEnviron, error) { 151 cred := cloud.NewCredential(cloud.OAuth1AuthType, map[string]string{ 152 "maas-oauth": "a:b:c", 153 }) 154 cloud := environs.CloudSpec{ 155 Type: "maas", 156 Name: "maas", 157 Endpoint: url, 158 Credential: &cred, 159 } 160 attrs := coretesting.FakeConfig().Merge(maasEnvAttrs) 161 suite.controllerUUID = coretesting.FakeControllerConfig().ControllerUUID() 162 cfg, err := config.New(config.NoDefaults, attrs) 163 if err != nil { 164 return nil, errors.Trace(err) 165 } 166 env, err := NewEnviron(cloud, cfg, getCapabilities) 167 if err != nil { 168 return nil, errors.Trace(err) 169 } 170 return env, nil 171 } 172 173 // makeEnviron creates a functional maasEnviron for a test. 174 func (suite *providerSuite) makeEnviron() *maasEnviron { 175 env, err := suite.makeEnvironWithURL( 176 suite.testMAASObject.TestServer.URL, 177 func(client *gomaasapi.MAASObject, serverURL string) (set.Strings, error) { 178 return set.NewStrings("network-deployment-ubuntu"), nil 179 }, 180 ) 181 if err != nil { 182 panic(err) 183 } 184 return env 185 } 186 187 func (suite *providerSuite) addNode(jsonText string) instance.Id { 188 node := suite.testMAASObject.TestServer.NewNode(jsonText) 189 resourceURI, _ := node.GetField("resource_uri") 190 return instance.Id(resourceURI) 191 } 192 193 func createSubnetInfo(subnetID, spaceID, ipRange uint) network.SubnetInfo { 194 return network.SubnetInfo{ 195 CIDR: fmt.Sprintf("192.168.%d.0/24", ipRange), 196 ProviderId: network.Id(strconv.Itoa(int(subnetID))), 197 SpaceProviderId: network.Id(fmt.Sprintf("%d", spaceID)), 198 } 199 } 200 201 func createSubnetWithSpace(ipRange, NICID uint, space string) gomaasapi.CreateSubnet { 202 var s gomaasapi.CreateSubnet 203 s.DNSServers = []string{"192.168.1.2"} 204 s.Name = fmt.Sprintf("maas-eth%d", NICID) 205 s.Space = space 206 s.GatewayIP = fmt.Sprintf("192.168.%v.1", ipRange) 207 s.CIDR = fmt.Sprintf("192.168.%v.0/24", ipRange) 208 return s 209 } 210 211 func (suite *providerSuite) addSubnet(c *gc.C, ipRange, spaceAndNICID uint, systemID string) uint { 212 space := fmt.Sprintf("space-%d", spaceAndNICID) 213 return suite.addSubnetWithSpace(c, ipRange, spaceAndNICID, space, systemID) 214 } 215 216 func (suite *providerSuite) addSubnetWithSpace(c *gc.C, ipRange, NICID uint, space string, systemID string) uint { 217 out := bytes.Buffer{} 218 err := json.NewEncoder(&out).Encode(createSubnetWithSpace(ipRange, NICID, space)) 219 c.Assert(err, jc.ErrorIsNil) 220 subnet := suite.testMAASObject.TestServer.NewSubnet(&out) 221 c.Assert(err, jc.ErrorIsNil) 222 223 other := gomaasapi.AddressRange{} 224 other.Start = fmt.Sprintf("192.168.%d.139", ipRange) 225 other.End = fmt.Sprintf("192.168.%d.149", ipRange) 226 other.Purpose = []string{"not-the-dynamic-range"} 227 suite.testMAASObject.TestServer.AddFixedAddressRange(subnet.ID, other) 228 229 ar := gomaasapi.AddressRange{} 230 ar.Start = fmt.Sprintf("192.168.%d.10", ipRange) 231 ar.End = fmt.Sprintf("192.168.%d.138", ipRange) 232 ar.Purpose = []string{"something", "dynamic-range"} 233 suite.testMAASObject.TestServer.AddFixedAddressRange(subnet.ID, ar) 234 if systemID != "" { 235 var nni gomaasapi.NodeNetworkInterface 236 nni.Name = subnet.Name 237 nni.Links = append(nni.Links, gomaasapi.NetworkLink{ 238 ID: uint(1), 239 Mode: "auto", 240 Subnet: subnet, 241 }) 242 suite.testMAASObject.TestServer.SetNodeNetworkLink(systemID, nni) 243 } 244 return subnet.ID 245 }