blob: c6c1617551cc678df4b27a646d9e62af9c94d9d6 [file] [log] [blame]
// Copyright 2012-2016 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package gomaasapi
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"regexp"
)
func getSpacesEndpoint(version string) string {
return fmt.Sprintf("/api/%s/spaces/", version)
}
// TestSpace is the MAAS API space representation
type TestSpace struct {
Name string `json:"name"`
Subnets []TestSubnet `json:"subnets"`
ResourceURI string `json:"resource_uri"`
ID uint `json:"id"`
}
// spacesHandler handles requests for '/api/<version>/spaces/'.
func spacesHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
values, err := url.ParseQuery(r.URL.RawQuery)
checkError(err)
op := values.Get("op")
if op != "" {
w.WriteHeader(http.StatusBadRequest)
return
}
spacesURLRE := regexp.MustCompile(`/spaces/(.+?)/`)
spacesURLMatch := spacesURLRE.FindStringSubmatch(r.URL.Path)
spacesURL := getSpacesEndpoint(server.version)
var ID uint
var gotID bool
if spacesURLMatch != nil {
ID, err = NameOrIDToID(spacesURLMatch[1], server.spaceNameToID, 1, uint(len(server.spaces)))
if err != nil {
http.NotFoundHandler().ServeHTTP(w, r)
return
}
gotID = true
}
switch r.Method {
case "GET":
w.Header().Set("Content-Type", "application/vnd.api+json")
if len(server.spaces) == 0 {
// Until a space is registered, behave as if the endpoint
// does not exist. This way we can simulate older MAAS
// servers that do not support spaces.
http.NotFoundHandler().ServeHTTP(w, r)
return
}
if r.URL.Path == spacesURL {
var spaces []*TestSpace
// Iterating by id rather than a dictionary iteration
// preserves the order of the spaces in the result.
for i := uint(1); i < server.nextSpace; i++ {
s, ok := server.spaces[i]
if ok {
server.setSubnetsOnSpace(s)
spaces = append(spaces, s)
}
}
err = json.NewEncoder(w).Encode(spaces)
} else if gotID == false {
w.WriteHeader(http.StatusBadRequest)
} else {
err = json.NewEncoder(w).Encode(server.spaces[ID])
}
checkError(err)
case "POST":
//server.NewSpace(r.Body)
case "PUT":
//server.UpdateSpace(r.Body)
case "DELETE":
delete(server.spaces, ID)
w.WriteHeader(http.StatusOK)
default:
w.WriteHeader(http.StatusBadRequest)
}
}
// CreateSpace is used to create new spaces on the server.
type CreateSpace struct {
Name string `json:"name"`
}
func decodePostedSpace(spaceJSON io.Reader) CreateSpace {
var postedSpace CreateSpace
decoder := json.NewDecoder(spaceJSON)
err := decoder.Decode(&postedSpace)
checkError(err)
return postedSpace
}
// NewSpace creates a space in the test server
func (server *TestServer) NewSpace(spaceJSON io.Reader) *TestSpace {
postedSpace := decodePostedSpace(spaceJSON)
newSpace := &TestSpace{Name: postedSpace.Name}
newSpace.ID = server.nextSpace
newSpace.ResourceURI = fmt.Sprintf("/api/%s/spaces/%d/", server.version, int(server.nextSpace))
server.spaces[server.nextSpace] = newSpace
server.spaceNameToID[newSpace.Name] = newSpace.ID
server.nextSpace++
return newSpace
}
// setSubnetsOnSpace fetches the subnets for the specified space and adds them
// to it.
func (server *TestServer) setSubnetsOnSpace(space *TestSpace) {
subnets := []TestSubnet{}
for i := uint(1); i < server.nextSubnet; i++ {
subnet, ok := server.subnets[i]
if ok && subnet.Space == space.Name {
subnets = append(subnets, subnet)
}
}
space.Subnets = subnets
}