Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MAAS2: handle fields that might be missing or null from the API #54

Merged
merged 4 commits into from
May 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion bootresource.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,8 @@ func bootResource_2_0(source map[string]interface{}) (*bootResource, error) {
"kflavor": schema.String(),
}
defaults := schema.Defaults{
"kflavor": "",
"subarches": "",
"kflavor": "",
}
checker := schema.FieldMap(fields, defaults)
coerced, err := checker.Coerce(source, nil)
Expand Down
1 change: 0 additions & 1 deletion bootresource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ var bootResourcesResponse = `
{
"architecture": "amd64/hwe-w",
"type": "Synced",
"subarches": "generic,hwe-p,hwe-q,hwe-r,hwe-s,hwe-t,hwe-u,hwe-v,hwe-w",
"kflavor": "generic",
"name": "ubuntu/trusty",
"id": 4,
Expand Down
15 changes: 10 additions & 5 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,9 @@ func interface_2_0(source map[string]interface{}) (*interface_, error) {
"name": schema.String(),
"type": schema.String(),
"enabled": schema.Bool(),
"tags": schema.List(schema.String()),
"tags": schema.OneOf(schema.Nil(""), schema.List(schema.String())),

"vlan": schema.StringMap(schema.Any()),
"vlan": schema.OneOf(schema.Nil(""), schema.StringMap(schema.Any())),
"links": schema.List(schema.StringMap(schema.Any())),

"mac_address": schema.OneOf(schema.Nil(""), schema.String()),
Expand All @@ -404,10 +404,15 @@ func interface_2_0(source map[string]interface{}) (*interface_, error) {
// From here we know that the map returned from the schema coercion
// contains fields of the right type.

vlan, err := vlan_2_0(valid["vlan"].(map[string]interface{}))
if err != nil {
return nil, errors.Trace(err)
var vlan *vlan
// If it's not an attribute map then we know it's nil from the schema check.
if vlanMap, ok := valid["vlan"].(map[string]interface{}); ok {
vlan, err = vlan_2_0(vlanMap)
if err != nil {
return nil, errors.Trace(err)
}
}

links, err := readLinkList(valid["links"].([]interface{}), link_2_0)
if err != nil {
return nil, errors.Trace(err)
Expand Down
53 changes: 53 additions & 0 deletions interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ func (*interfaceSuite) TestReadInterfacesBadSchema(c *gc.C) {
c.Assert(err, gc.ErrorMatches, `interface 0: interface 2.0 schema check failed: .*`)
}

func (*interfaceSuite) TestReadInterfacesNulls(c *gc.C) {
iface, err := readInterface(twoDotOh, parseJSON(c, interfaceNullsResponse))
c.Assert(err, jc.ErrorIsNil)

c.Check(iface.MACAddress(), gc.Equals, "")
c.Check(iface.Tags(), jc.DeepEquals, []string{})
c.Check(iface.VLAN(), gc.IsNil)
}

func (s *interfaceSuite) checkInterface(c *gc.C, iface *interface_) {
c.Check(iface.ID(), gc.Equals, 40)
c.Check(iface.Name(), gc.Equals, "eth0")
Expand Down Expand Up @@ -438,5 +447,49 @@ const (
}
]
}
`
interfaceNullsResponse = `
{
"effective_mtu": 1500,
"mac_address": null,
"children": ["eth0.1", "eth0.2"],
"discovered": [],
"params": "some params",
"vlan": null,
"name": "eth0",
"enabled": true,
"parents": ["bond0"],
"id": 40,
"type": "physical",
"resource_uri": "/MAAS/api/2.0/nodes/4y3ha6/interfaces/40/",
"tags": null,
"links": [
{
"id": 69,
"mode": "auto",
"subnet": {
"resource_uri": "/MAAS/api/2.0/subnets/1/",
"id": 1,
"rdns_mode": 2,
"vlan": {
"resource_uri": "/MAAS/api/2.0/vlans/1/",
"id": 1,
"secondary_rack": null,
"mtu": 1500,
"primary_rack": "4y3h7n",
"name": "untagged",
"fabric": "fabric-0",
"dhcp_on": true,
"vid": 0
},
"dns_servers": [],
"space": "space-0",
"name": "192.168.100.0/24",
"gateway_ip": "192.168.100.1",
"cidr": "192.168.100.0/24"
}
}
]
}
`
)
17 changes: 11 additions & 6 deletions machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,9 @@ func machine_2_0(source map[string]interface{}) (*machine, error) {
"ip_addresses": schema.List(schema.String()),
"power_state": schema.String(),
"status_name": schema.String(),
"status_message": schema.String(),
"status_message": schema.OneOf(schema.Nil(""), schema.String()),

"boot_interface": schema.StringMap(schema.Any()),
"boot_interface": schema.OneOf(schema.Nil(""), schema.StringMap(schema.Any())),
"interface_set": schema.List(schema.StringMap(schema.Any())),
"zone": schema.StringMap(schema.Any()),

Expand All @@ -430,10 +430,14 @@ func machine_2_0(source map[string]interface{}) (*machine, error) {
// From here we know that the map returned from the schema coercion
// contains fields of the right type.

bootInterface, err := interface_2_0(valid["boot_interface"].(map[string]interface{}))
if err != nil {
return nil, errors.Trace(err)
var bootInterface *interface_
if ifaceMap, ok := valid["boot_interface"].(map[string]interface{}); ok {
bootInterface, err = interface_2_0(ifaceMap)
if err != nil {
return nil, errors.Trace(err)
}
}

interfaceSet, err := readInterfaceList(valid["interface_set"].([]interface{}), interface_2_0)
if err != nil {
return nil, errors.Trace(err)
Expand All @@ -451,6 +455,7 @@ func machine_2_0(source map[string]interface{}) (*machine, error) {
return nil, errors.Trace(err)
}
architecture, _ := valid["architecture"].(string)
statusMessage, _ := valid["status_message"].(string)
result := &machine{
resourceURI: valid["resource_uri"].(string),

Expand All @@ -468,7 +473,7 @@ func machine_2_0(source map[string]interface{}) (*machine, error) {
ipAddresses: convertToStringSlice(valid["ip_addresses"]),
powerState: valid["power_state"].(string),
statusName: valid["status_name"].(string),
statusMessage: valid["status_message"].(string),
statusMessage: statusMessage,

bootInterface: bootInterface,
interfaceSet: interfaceSet,
Expand Down
9 changes: 7 additions & 2 deletions machine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,19 @@ func (*machineSuite) TestReadMachines(c *gc.C) {
c.Assert(machine.PhysicalBlockDevice(id+5), gc.IsNil)
}

func (*machineSuite) TestReadMachinesNilArch(c *gc.C) {
func (*machineSuite) TestReadMachinesNilValues(c *gc.C) {
json := parseJSON(c, machinesResponse)
json.([]interface{})[0].(map[string]interface{})["architecture"] = nil
data := json.([]interface{})[0].(map[string]interface{})
data["architecture"] = nil
data["status_message"] = nil
data["boot_interface"] = nil
machines, err := readMachines(twoDotOh, json)
c.Assert(err, jc.ErrorIsNil)
c.Assert(machines, gc.HasLen, 3)
machine := machines[0]
c.Check(machine.Architecture(), gc.Equals, "")
c.Check(machine.StatusMessage(), gc.Equals, "")
c.Check(machine.BootInterface(), gc.IsNil)
}

func (*machineSuite) TestLowVersion(c *gc.C) {
Expand Down