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

Added functions related to tags in testservice #64

Merged
merged 2 commits into from
Mar 12, 2017
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
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