1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
9
"github.com/juju/errors"
10
"github.com/juju/testing"
11
jc "github.com/juju/testing/checkers"
12
"github.com/juju/version"
13
gc "gopkg.in/check.v1"
16
type deviceSuite struct {
20
var _ = gc.Suite(&deviceSuite{})
22
func (*deviceSuite) TestReadDevicesBadSchema(c *gc.C) {
23
_, err := readDevices(twoDotOh, "wat?")
24
c.Check(err, jc.Satisfies, IsDeserializationError)
25
c.Assert(err.Error(), gc.Equals, `device base schema check failed: expected list, got string("wat?")`)
28
func (*deviceSuite) TestReadDevices(c *gc.C) {
29
devices, err := readDevices(twoDotOh, parseJSON(c, devicesResponse))
30
c.Assert(err, jc.ErrorIsNil)
31
c.Assert(devices, gc.HasLen, 1)
34
c.Check(device.SystemID(), gc.Equals, "4y3haf")
35
c.Check(device.Hostname(), gc.Equals, "furnacelike-brittney")
36
c.Check(device.FQDN(), gc.Equals, "furnacelike-brittney.maas")
37
c.Check(device.IPAddresses(), jc.DeepEquals, []string{"192.168.100.11"})
39
c.Check(zone, gc.NotNil)
40
c.Check(zone.Name(), gc.Equals, "default")
43
func (*deviceSuite) TestLowVersion(c *gc.C) {
44
_, err := readDevices(version.MustParse("1.9.0"), parseJSON(c, devicesResponse))
45
c.Assert(err, jc.Satisfies, IsUnsupportedVersionError)
48
func (*deviceSuite) TestHighVersion(c *gc.C) {
49
devices, err := readDevices(version.MustParse("2.1.9"), parseJSON(c, devicesResponse))
50
c.Assert(err, jc.ErrorIsNil)
51
c.Assert(devices, gc.HasLen, 1)
54
func (s *deviceSuite) TestInterfaceSet(c *gc.C) {
55
server, device := s.getServerAndDevice(c)
56
server.AddGetResponse(device.interfacesURI(), http.StatusOK, interfacesResponse)
57
ifaces := device.InterfaceSet()
58
c.Assert(ifaces, gc.HasLen, 2)
61
type fakeVLAN struct {
66
func (f *fakeVLAN) ID() int {
70
func (s *controllerSuite) TestCreateInterfaceArgsValidate(c *gc.C) {
71
for i, test := range []struct {
72
args CreateInterfaceArgs
75
errText: "missing Name not valid",
77
args: CreateInterfaceArgs{Name: "eth3"},
78
errText: "missing MACAddress not valid",
80
args: CreateInterfaceArgs{Name: "eth3", MACAddress: "a-mac-address"},
81
errText: `missing VLAN not valid`,
83
args: CreateInterfaceArgs{Name: "eth3", MACAddress: "a-mac-address", VLAN: &fakeVLAN{}},
86
err := test.args.Validate()
87
if test.errText == "" {
88
c.Check(err, jc.ErrorIsNil)
90
c.Check(err, jc.Satisfies, errors.IsNotValid)
91
c.Check(err.Error(), gc.Equals, test.errText)
96
func (s *deviceSuite) TestCreateInterfaceValidates(c *gc.C) {
97
_, device := s.getServerAndDevice(c)
98
_, err := device.CreateInterface(CreateInterfaceArgs{})
99
c.Assert(err, jc.Satisfies, errors.IsNotValid)
102
func (s *deviceSuite) TestCreateInterface(c *gc.C) {
103
server, device := s.getServerAndDevice(c)
104
server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusOK, interfaceResponse)
106
iface, err := device.CreateInterface(CreateInterfaceArgs{
108
MACAddress: "some-mac-address",
109
VLAN: &fakeVLAN{id: 33},
110
Tags: []string{"foo", "bar"},
112
c.Assert(err, jc.ErrorIsNil)
113
c.Assert(iface, gc.NotNil)
115
request := server.LastRequest()
116
form := request.PostForm
117
c.Assert(form.Get("name"), gc.Equals, "eth43")
118
c.Assert(form.Get("mac_address"), gc.Equals, "some-mac-address")
119
c.Assert(form.Get("vlan"), gc.Equals, "33")
120
c.Assert(form.Get("tags"), gc.Equals, "foo,bar")
123
func minimalCreateInterfaceArgs() CreateInterfaceArgs {
124
return CreateInterfaceArgs{
126
MACAddress: "some-mac-address",
127
VLAN: &fakeVLAN{id: 33},
131
func (s *deviceSuite) TestCreateInterfaceNotFound(c *gc.C) {
132
server, device := s.getServerAndDevice(c)
133
server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusNotFound, "can't find device")
134
_, err := device.CreateInterface(minimalCreateInterfaceArgs())
135
c.Assert(err, jc.Satisfies, IsBadRequestError)
136
c.Assert(err.Error(), gc.Equals, "can't find device")
139
func (s *deviceSuite) TestCreateInterfaceConflict(c *gc.C) {
140
server, device := s.getServerAndDevice(c)
141
server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusConflict, "device not allocated")
142
_, err := device.CreateInterface(minimalCreateInterfaceArgs())
143
c.Assert(err, jc.Satisfies, IsBadRequestError)
144
c.Assert(err.Error(), gc.Equals, "device not allocated")
147
func (s *deviceSuite) TestCreateInterfaceForbidden(c *gc.C) {
148
server, device := s.getServerAndDevice(c)
149
server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusForbidden, "device not yours")
150
_, err := device.CreateInterface(minimalCreateInterfaceArgs())
151
c.Assert(err, jc.Satisfies, IsPermissionError)
152
c.Assert(err.Error(), gc.Equals, "device not yours")
155
func (s *deviceSuite) TestCreateInterfaceServiceUnavailable(c *gc.C) {
156
server, device := s.getServerAndDevice(c)
157
server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusServiceUnavailable, "no ip addresses available")
158
_, err := device.CreateInterface(minimalCreateInterfaceArgs())
159
c.Assert(err, jc.Satisfies, IsCannotCompleteError)
160
c.Assert(err.Error(), gc.Equals, "no ip addresses available")
163
func (s *deviceSuite) TestCreateInterfaceUnknown(c *gc.C) {
164
server, device := s.getServerAndDevice(c)
165
server.AddPostResponse(device.interfacesURI()+"?op=create_physical", http.StatusMethodNotAllowed, "wat?")
166
_, err := device.CreateInterface(minimalCreateInterfaceArgs())
167
c.Assert(err, jc.Satisfies, IsUnexpectedError)
168
c.Assert(err.Error(), gc.Equals, "unexpected: ServerError: 405 Method Not Allowed (wat?)")
171
func (s *deviceSuite) getServerAndDevice(c *gc.C) (*SimpleTestServer, *device) {
172
server, controller := createTestServerController(c, s)
173
server.AddGetResponse("/api/2.0/devices/", http.StatusOK, devicesResponse)
175
devices, err := controller.Devices(DevicesArgs{})
176
c.Assert(err, jc.ErrorIsNil)
177
c.Assert(devices, gc.HasLen, 1)
178
return server, devices[0].(*device)
181
func (s *deviceSuite) TestDelete(c *gc.C) {
182
server, device := s.getServerAndDevice(c)
183
// Successful delete is 204 - StatusNoContent
184
server.AddDeleteResponse(device.resourceURI, http.StatusNoContent, "")
185
err := device.Delete()
186
c.Assert(err, jc.ErrorIsNil)
189
func (s *deviceSuite) TestDelete404(c *gc.C) {
190
_, device := s.getServerAndDevice(c)
192
err := device.Delete()
193
c.Assert(err, jc.Satisfies, IsNoMatchError)
196
func (s *deviceSuite) TestDeleteForbidden(c *gc.C) {
197
server, device := s.getServerAndDevice(c)
198
server.AddDeleteResponse(device.resourceURI, http.StatusForbidden, "")
199
err := device.Delete()
200
c.Assert(err, jc.Satisfies, IsPermissionError)
203
func (s *deviceSuite) TestDeleteUnknown(c *gc.C) {
204
server, device := s.getServerAndDevice(c)
205
server.AddDeleteResponse(device.resourceURI, http.StatusConflict, "")
206
err := device.Delete()
207
c.Assert(err, jc.Satisfies, IsUnexpectedError)
215
"resource_uri": "/MAAS/api/2.0/zones/default/",
219
"resource_record_count": 0,
220
"resource_uri": "/MAAS/api/2.0/domains/0/",
221
"authoritative": true,
226
"node_type_name": "Device",
228
"hostname": "furnacelike-brittney",
230
"resource_uri": "/MAAS/api/2.0/devices/4y3haf/",
231
"ip_addresses": ["192.168.100.11"],
234
"fqdn": "furnacelike-brittney.maas",
235
"system_id": "4y3haf",
239
"resource_uri": "/MAAS/api/2.0/nodes/4y3haf/interfaces/48/",
241
"mac_address": "78:f0:f1:16:a7:46",
244
"effective_mtu": 1500,
250
"secondary_rack": null,
252
"fabric": "fabric-0",
254
"primary_rack": "4y3h7n",
255
"resource_uri": "/MAAS/api/2.0/vlans/1/",
256
"external_dhcp": null,
266
"resource_uri": "/MAAS/api/2.0/nodes/4y3haf/interfaces/49/",
268
"mac_address": "15:34:d3:2d:f7:a7",
271
"effective_mtu": 1500,
282
"secondary_rack": null,
284
"fabric": "fabric-0",
286
"primary_rack": "4y3h7n",
287
"resource_uri": "/MAAS/api/2.0/vlans/1/",
288
"external_dhcp": null,
300
devicesResponse = "[" + deviceResponse + "]"