blob: c6c1617551cc678df4b27a646d9e62af9c94d9d6 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2012-2016 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package gomaasapi
5
6import (
7 "encoding/json"
8 "fmt"
9 "io"
10 "net/http"
11 "net/url"
12 "regexp"
13)
14
15func getSpacesEndpoint(version string) string {
16 return fmt.Sprintf("/api/%s/spaces/", version)
17}
18
19// TestSpace is the MAAS API space representation
20type TestSpace struct {
21 Name string `json:"name"`
22 Subnets []TestSubnet `json:"subnets"`
23 ResourceURI string `json:"resource_uri"`
24 ID uint `json:"id"`
25}
26
27// spacesHandler handles requests for '/api/<version>/spaces/'.
28func spacesHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
29 values, err := url.ParseQuery(r.URL.RawQuery)
30 checkError(err)
31 op := values.Get("op")
32 if op != "" {
33 w.WriteHeader(http.StatusBadRequest)
34 return
35 }
36
37 spacesURLRE := regexp.MustCompile(`/spaces/(.+?)/`)
38 spacesURLMatch := spacesURLRE.FindStringSubmatch(r.URL.Path)
39 spacesURL := getSpacesEndpoint(server.version)
40
41 var ID uint
42 var gotID bool
43 if spacesURLMatch != nil {
44 ID, err = NameOrIDToID(spacesURLMatch[1], server.spaceNameToID, 1, uint(len(server.spaces)))
45
46 if err != nil {
47 http.NotFoundHandler().ServeHTTP(w, r)
48 return
49 }
50
51 gotID = true
52 }
53
54 switch r.Method {
55 case "GET":
56 w.Header().Set("Content-Type", "application/vnd.api+json")
57 if len(server.spaces) == 0 {
58 // Until a space is registered, behave as if the endpoint
59 // does not exist. This way we can simulate older MAAS
60 // servers that do not support spaces.
61 http.NotFoundHandler().ServeHTTP(w, r)
62 return
63 }
64
65 if r.URL.Path == spacesURL {
66 var spaces []*TestSpace
67 // Iterating by id rather than a dictionary iteration
68 // preserves the order of the spaces in the result.
69 for i := uint(1); i < server.nextSpace; i++ {
70 s, ok := server.spaces[i]
71 if ok {
72 server.setSubnetsOnSpace(s)
73 spaces = append(spaces, s)
74 }
75 }
76 err = json.NewEncoder(w).Encode(spaces)
77 } else if gotID == false {
78 w.WriteHeader(http.StatusBadRequest)
79 } else {
80 err = json.NewEncoder(w).Encode(server.spaces[ID])
81 }
82 checkError(err)
83 case "POST":
84 //server.NewSpace(r.Body)
85 case "PUT":
86 //server.UpdateSpace(r.Body)
87 case "DELETE":
88 delete(server.spaces, ID)
89 w.WriteHeader(http.StatusOK)
90 default:
91 w.WriteHeader(http.StatusBadRequest)
92 }
93}
94
95// CreateSpace is used to create new spaces on the server.
96type CreateSpace struct {
97 Name string `json:"name"`
98}
99
100func decodePostedSpace(spaceJSON io.Reader) CreateSpace {
101 var postedSpace CreateSpace
102 decoder := json.NewDecoder(spaceJSON)
103 err := decoder.Decode(&postedSpace)
104 checkError(err)
105 return postedSpace
106}
107
108// NewSpace creates a space in the test server
109func (server *TestServer) NewSpace(spaceJSON io.Reader) *TestSpace {
110 postedSpace := decodePostedSpace(spaceJSON)
111 newSpace := &TestSpace{Name: postedSpace.Name}
112 newSpace.ID = server.nextSpace
113 newSpace.ResourceURI = fmt.Sprintf("/api/%s/spaces/%d/", server.version, int(server.nextSpace))
114 server.spaces[server.nextSpace] = newSpace
115 server.spaceNameToID[newSpace.Name] = newSpace.ID
116
117 server.nextSpace++
118 return newSpace
119}
120
121// setSubnetsOnSpace fetches the subnets for the specified space and adds them
122// to it.
123func (server *TestServer) setSubnetsOnSpace(space *TestSpace) {
124 subnets := []TestSubnet{}
125 for i := uint(1); i < server.nextSubnet; i++ {
126 subnet, ok := server.subnets[i]
127 if ok && subnet.Space == space.Name {
128 subnets = append(subnets, subnet)
129 }
130 }
131 space.Subnets = subnets
132}