Skip to content

Commit

Permalink
Merge pull request #64 from YujiOshima/addtag
Browse files Browse the repository at this point in the history
Added functions related to tags in testservice

Added TestServer functions on api of tag shown below to testservice.

* GET /api/1.0/tags/ op=list
* POST /api/1.0/tags/ op=new
* GET /api/1.0/tags/{name}/
* GET /api/1.0/tags/{name}/ op=nodes
* POST /api/1.0/tags/{name}/ op=update_nodes
* PUT /api/1.0/tags/{name}/
* DELETE /api/1.0/tags/{name}/
  • Loading branch information
jujubot authored Mar 12, 2017
2 parents cfbc096 + 82cbb51 commit 31d8415
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 1 deletion.
196 changes: 195 additions & 1 deletion testservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,10 @@ type TestServer struct {
ipAddressesPerNetwork map[string][]string
version string
macAddressesPerNetwork map[string]map[string]JSONObject
tagsPerNode map[string][]string
nodeDetails map[string]string
zones map[string]JSONObject
tags map[string]JSONObject
// bootImages is a map of nodegroup UUIDs to boot-image objects.
bootImages map[string][]JSONObject
// nodegroupsInterfaces is a map of nodegroup UUIDs to interface
Expand Down Expand Up @@ -209,6 +211,19 @@ func getZonesEndpoint(version string) string {
return fmt.Sprintf("/api/%s/zones/", version)
}

func getTagsEndpoint(version string) string {
return fmt.Sprintf("/api/%s/tags/", version)
}

func getTagURL(version, tag_name string) string {
return fmt.Sprintf("/api/%s/tags/%s/", version, tag_name)
}

func getTagURLRE(version string) *regexp.Regexp {
reString := fmt.Sprintf("^/api/%s/tags/([^/]*)/$", regexp.QuoteMeta(version))
return regexp.MustCompile(reString)
}

// Clear clears all the fake data stored and recorded by the test server
// (nodes, recorded operations, etc.).
func (server *TestServer) Clear() {
Expand All @@ -223,11 +238,13 @@ func (server *TestServer) Clear() {
server.networks = make(map[string]MAASObject)
server.networksPerNode = make(map[string][]string)
server.ipAddressesPerNetwork = make(map[string][]string)
server.tagsPerNode = make(map[string][]string)
server.macAddressesPerNetwork = make(map[string]map[string]JSONObject)
server.nodeDetails = make(map[string]string)
server.bootImages = make(map[string][]JSONObject)
server.nodegroupsInterfaces = make(map[string][]JSONObject)
server.zones = make(map[string]JSONObject)
server.tags = make(map[string]JSONObject)
server.versionJSON = `{"capabilities": ["networks-management","static-ipaddresses","devices-management","network-deployment-ubuntu"]}`
server.devices = make(map[string]*TestDevice)
server.subnets = make(map[uint]TestSubnet)
Expand Down Expand Up @@ -546,6 +563,17 @@ func (server *TestServer) AddZone(name, description string) {
server.zones[name] = obj
}

// AddTah adds a tag to the server.
func (server *TestServer) AddTag(name, comment string) {
attrs := map[string]interface{}{
"name": name,
"comment": comment,
resourceURI: getTagURL(server.version, name),
}
obj := maasify(server.client, attrs)
server.tags[name] = obj
}

func (server *TestServer) AddDevice(device *TestDevice) {
server.devices[device.SystemId] = device
}
Expand Down Expand Up @@ -601,6 +629,12 @@ func NewTestServer(version string) *TestServer {
zonesHandler(server, w, r)
})

// Register handler for '/api/<version>/zones/*'.
tagsURL := getTagsEndpoint(server.version)
serveMux.HandleFunc(tagsURL, func(w http.ResponseWriter, r *http.Request) {
tagsHandler(server, w, r)
})

subnetsURL := getSubnetsEndpoint(server.version)
serveMux.HandleFunc(subnetsURL, func(w http.ResponseWriter, r *http.Request) {
subnetsHandler(server, w, r)
Expand Down Expand Up @@ -1015,7 +1049,7 @@ func findFreeNode(server *TestServer, filter url.Values) *MAASObject {
for systemID, node := range server.Nodes() {
_, present := server.OwnedNodes()[systemID]
if !present {
var agentName, nodeName, zoneName, mem, cpuCores, arch string
var agentName, nodeName, zoneName, tagName, mem, cpuCores, arch string
for k := range filter {
switch k {
case "agent_name":
Expand All @@ -1024,6 +1058,8 @@ func findFreeNode(server *TestServer, filter url.Values) *MAASObject {
nodeName = filter.Get(k)
case "zone":
zoneName = filter.Get(k)
case "tags":
tagName = filter.Get(k)
case "mem":
mem = filter.Get(k)
case "arch":
Expand All @@ -1038,6 +1074,9 @@ func findFreeNode(server *TestServer, filter url.Values) *MAASObject {
if zoneName != "" && !matchField(node, "zone", zoneName) {
continue
}
if tagName != "" && !matchField(node, "tag_names", tagName) {
continue
}
if mem != "" && !matchNumericField(node, "memory", mem) {
continue
}
Expand Down Expand Up @@ -1679,3 +1718,158 @@ func zonesHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, string(res))
}

// tagsHandler handles requests for '/api/<version>/tags/'.
func tagsHandler(server *TestServer, w http.ResponseWriter, r *http.Request) {
tagURLRE := getTagURLRE(server.version)
tagURLMatch := tagURLRE.FindStringSubmatch(r.URL.Path)
tagsURL := getTagsEndpoint(server.version)
err := r.ParseForm()
checkError(err)
values := r.PostForm
names, hasName := getValues(values, "name")
quary, err := url.ParseQuery(r.URL.RawQuery)
checkError(err)
op := quary.Get("op")
if r.URL.Path == tagsURL {
if r.Method == "GET" {
tags := make([]JSONObject, 0, len(server.zones))
for _, tag := range server.tags {
tags = append(tags, tag)
}
res, err := json.MarshalIndent(tags, "", " ")
checkError(err)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, string(res))
} else if r.Method == "POST" && hasName {
if op == "" || op == "new" {
for _, name := range names {
newTagHandler(server, w, r, name, values)
}
} else {
w.WriteHeader(http.StatusBadRequest)
}
} else {
w.WriteHeader(http.StatusBadRequest)
}
} else if tagURLMatch != nil {
// Request for a single tag
tagHandler(server, w, r, tagURLMatch[1], op, values)
} else {
http.NotFoundHandler().ServeHTTP(w, r)
}
}

// newTagHandler creates, stores and returns new tag.
func newTagHandler(server *TestServer, w http.ResponseWriter, r *http.Request, name string, values url.Values) {
comment, hascomment := getValue(values, "comment")
var attrs map[string]interface{}
if hascomment {
attrs = map[string]interface{}{
"name": name,
"comment": comment,
resourceURI: getTagURL(server.version, name),
}
} else {
attrs = map[string]interface{}{
"name": name,
resourceURI: getTagURL(server.version, name),
}
}
obj := maasify(server.client, attrs)
server.tags[name] = obj
res, err := json.MarshalIndent(obj, "", " ")
checkError(err)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, res)
}

// tagHandler handles requests for '/api/<version>/tag/<name>/'.
func tagHandler(server *TestServer, w http.ResponseWriter, r *http.Request, name string, operation string, values url.Values) {
switch r.Method {
case "GET":
switch operation {
case "node":
var convertedNodes = []map[string]JSONObject{}
for systemID, node := range server.nodes {
for _, nodetag := range server.tagsPerNode[systemID] {
if name == nodetag {
convertedNodes = append(convertedNodes, node.GetMap())
}
}
}
res, err := json.MarshalIndent(convertedNodes, "", " ")
checkError(err)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, string(res))
default:
res, err := json.MarshalIndent(server.tags[name], "", " ")
checkError(err)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, string(res))
}
case "POST":
if operation == "update_nodes" {
addNodes, hasAdd := getValues(values, "add")
delNodes, hasRemove := getValues(values, "remove")
addremovecount := map[string]int{"add": len(addNodes), "remove": len(delNodes)}
if !hasAdd && !hasRemove {
w.WriteHeader(http.StatusBadRequest)
return
}
for _, systemID := range addNodes {
_, ok := server.nodes[systemID]
if !ok {
w.WriteHeader(http.StatusBadRequest)
return
}
var newTags []string
for _, tag := range server.tagsPerNode[systemID] {
if tag != name {
newTags = append(newTags, tag)
}
}
server.tagsPerNode[systemID] = append(newTags, name)
newTagsObj := make([]JSONObject, len(server.tagsPerNode[systemID]))
for i, tagsofnode := range server.tagsPerNode[systemID] {
newTagsObj[i] = server.tags[tagsofnode]
}
tagNamesObj := JSONObject{
value: newTagsObj,
}
server.nodes[systemID].values["tag_names"] = tagNamesObj
}
for _, systemID := range delNodes {
_, ok := server.nodes[systemID]
if !ok {
w.WriteHeader(http.StatusBadRequest)
return
}
var newTags []string
for _, tag := range server.tagsPerNode[systemID] {
if tag != name {
newTags = append(newTags, tag)
}
}
server.tagsPerNode[systemID] = newTags
newTagsObj := make([]JSONObject, len(server.tagsPerNode[systemID]))
for i, tagsofnode := range server.tagsPerNode[systemID] {
newTagsObj[i] = server.tags[tagsofnode]
}
tagNamesObj := JSONObject{
value: newTagsObj,
}
server.nodes[systemID].values["tag_names"] = tagNamesObj
}
res, err := json.MarshalIndent(addremovecount, "", " ")
checkError(err)
w.WriteHeader(http.StatusOK)
fmt.Fprint(w, string(res))
}
case "PUT":
newTagHandler(server, w, r, name, values)
case "DELETE":
delete(server.tags, name)
w.WriteHeader(http.StatusOK)
}
}
43 changes: 43 additions & 0 deletions testservice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1920,6 +1920,36 @@ func (suite *TestMAASObjectSuite) TestListZones(c *C) {
c.Assert(m, DeepEquals, expected)
}

func (suite *TestMAASObjectSuite) TestListTags(c *C) {
expected := map[string]string{
"tag0": "Develop",
"tag1": "Lack01",
}
for name, comment := range expected {
suite.TestMAASObject.TestServer.AddTag(name, comment)
}

result, err := suite.TestMAASObject.GetSubObject("tags").CallGet("", nil)
c.Assert(err, IsNil)
c.Assert(result, NotNil)

list, err := result.GetArray()
c.Assert(err, IsNil)
c.Assert(list, HasLen, len(expected))

m := make(map[string]string)
for _, item := range list {
itemMap, err := item.GetMap()
c.Assert(err, IsNil)
name, err := itemMap["name"].GetString()
c.Assert(err, IsNil)
comment, err := itemMap["comment"].GetString()
c.Assert(err, IsNil)
m[name] = comment
}
c.Assert(m, DeepEquals, expected)
}

func (suite *TestMAASObjectSuite) TestAcquireNodeZone(c *C) {
suite.TestMAASObject.TestServer.AddZone("z0", "rox")
suite.TestMAASObject.TestServer.AddZone("z1", "sux")
Expand Down Expand Up @@ -2001,6 +2031,19 @@ func (suite *TestMAASObjectSuite) TestAcquireFilterArch(c *C) {
c.Assert(arch, Equals, "arm/generic")
}

func (suite *TestMAASObjectSuite) TestAcquireFilterTag(c *C) {
suite.TestMAASObject.TestServer.NewNode(`{"system_id": "n0", "tag_names": "Develop"}`)
suite.TestMAASObject.TestServer.NewNode(`{"system_id": "n1", "tag_names": "GPU"}`)
nodeListing := suite.TestMAASObject.GetSubObject("nodes")
jsonResponse, err := nodeListing.CallPost("acquire", url.Values{"tags": []string{"GPU"}})
c.Assert(err, IsNil)
acquiredNode, err := jsonResponse.GetMAASObject()
c.Assert(err, IsNil)
fmt.Printf("%v\n", acquiredNode)
tag, _ := acquiredNode.GetField("tag_names")
c.Assert(tag, Equals, "GPU")
}

func (suite *TestMAASObjectSuite) TestDeploymentStatus(c *C) {
suite.TestMAASObject.TestServer.NewNode(`{"system_id": "n0", "status": "6"}`)
suite.TestMAASObject.TestServer.NewNode(`{"system_id": "n1", "status": "1"}`)
Expand Down

0 comments on commit 31d8415

Please sign in to comment.