launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #15015
[Merge] lp:~rvb/maas/gomaasapi-junction into lp:~maas-maintainers/maas/gomaasapi
Raphaël Badin has proposed merging lp:~rvb/maas/gomaasapi-junction into lp:~maas-maintainers/maas/gomaasapi.
Commit message:
Implement PUT/POST/DELETE method. Update live_example for a full-scale test.
- Update jsonMAASObject to make it contain a baseURL. The reason behind this is that the 'resource_uri' needs to be concatenated with the baseURL to form the complete URL. Updated maasify and the related tests.
- Implement the client's Put/Post/Delete methods and created "delegators" methods in jsonMAASObject.
- remove ListNodes and create a utility (NewServer) to create a new server object implementing MAASObject.
- the example in example/live_example.go now does the 4 types of requests (GET/POST/DELETE/PUT).
Requested reviews:
MAAS Maintainers (maas-maintainers)
For more details, see:
https://code.launchpad.net/~rvb/maas/gomaasapi-junction/+merge/145001
This was pre-imp'ed with Jeroen this morning.
To run the example, start a MAAS dev server, grab the API key, then run:
go run example/live_example.go <<EOF
you:api:key
http://0.0.0.0:5240/api/1.0
EOF
--
https://code.launchpad.net/~rvb/maas/gomaasapi-junction/+merge/145001
Your team MAAS Maintainers is requested to review the proposed merge of lp:~rvb/maas/gomaasapi-junction into lp:~maas-maintainers/maas/gomaasapi.
=== modified file 'client.go'
--- client.go 2013-01-25 08:39:47 +0000
+++ client.go 2013-01-25 18:09:19 +0000
@@ -5,6 +5,7 @@
import (
"errors"
+ "fmt"
"io/ioutil"
"net/http"
"net/url"
@@ -15,6 +16,10 @@
Signer OAuthSigner
}
+const (
+ operationParamName = "op"
+)
+
func (client Client) dispatchRequest(request *http.Request) ([]byte, error) {
client.Signer.OAuthSign(request)
httpClient := http.Client{}
@@ -32,7 +37,15 @@
return body, nil
}
-func (client Client) Get(URL string, parameters url.Values) ([]byte, error) {
+func (client Client) Get(URL string, operation string, parameters url.Values) ([]byte, error) {
+ opParameter := parameters.Get(operationParamName)
+ if opParameter != "" {
+ errString := fmt.Sprintf("The parameters contain a value for '%s' which is reserved parameter.")
+ return nil, errors.New(errString)
+ }
+ if operation != "" {
+ parameters.Set(operationParamName, operation)
+ }
queryUrl := URL + "?" + parameters.Encode()
request, err := http.NewRequest("GET", queryUrl, nil)
if err != nil {
@@ -41,16 +54,37 @@
return client.dispatchRequest(request)
}
-func (client Client) Post(URL string, parameters url.Values) ([]byte, error) {
- // Not implemented.
- return []byte{}, nil
-}
+func (client Client) modification(method string, URL string, parameters url.Values) ([]byte, error) {
+ request, err := http.NewRequest(method, URL, strings.NewReader(string(parameters.Encode())))
+ if err != nil {
+ return nil, err
+ }
+ request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ if err != nil {
+ return nil, err
+ }
+ return client.dispatchRequest(request)
+}
+
+func (client Client) Post(URL string, operation string, parameters url.Values) ([]byte, error) {
+ queryParams := url.Values{operationParamName: {operation}}
+ queryURL := URL + "?" + queryParams.Encode()
+ return client.modification("POST", queryURL, parameters)
+}
+
func (client Client) Put(URL string, parameters url.Values) ([]byte, error) {
- // Not implemented.
- return []byte{}, nil
+ return client.modification("PUT", URL, parameters)
}
-func (client Client) Delete(URL string, parameters url.Values) error {
- // Not implemented.
+
+func (client Client) Delete(URL string) error {
+ request, err := http.NewRequest("DELETE", URL, strings.NewReader(""))
+ if err != nil {
+ return err
+ }
+ _, err2 := client.dispatchRequest(request)
+ if err2 != nil {
+ return err2
+ }
return nil
}
=== modified file 'client_test.go'
--- client_test.go 2013-01-25 09:43:44 +0000
+++ client_test.go 2013-01-25 18:09:19 +0000
@@ -34,7 +34,7 @@
result, err := client.dispatchRequest(request)
- c.Assert(err, IsNil)
+ c.Check(err, IsNil)
c.Check(string(result), Equals, expectedResult)
c.Check((*server.requestHeader)["Authorization"][0], Matches, "^OAuth .*")
}
@@ -43,15 +43,72 @@
URI := "/some/url"
expectedResult := "expected:result"
client, _ := NewAnonymousClient()
- params := url.Values{"op": {"list"}}
- fullURI := URI + "?op=list"
- server := newSingleServingServer(fullURI, expectedResult, http.StatusOK)
- defer server.Close()
-
- result, err := client.Get(server.URL+URI, params)
-
- c.Assert(err, IsNil)
- c.Check(string(result), Equals, expectedResult)
+ params := url.Values{"test": {"123"}}
+ fullURI := URI + "?test=123"
+ server := newSingleServingServer(fullURI, expectedResult, http.StatusOK)
+ defer server.Close()
+
+ result, err := client.Get(server.URL+URI, "", params)
+
+ c.Check(err, IsNil)
+ c.Check(string(result), Equals, expectedResult)
+}
+
+func (suite *GomaasapiTestSuite) TestClientGetFormatsOperationAsGetParameter(c *C) {
+ URI := "/some/url"
+ expectedResult := "expected:result"
+ client, _ := NewAnonymousClient()
+ fullURI := URI + "?op=list"
+ server := newSingleServingServer(fullURI, expectedResult, http.StatusOK)
+ defer server.Close()
+
+ result, err := client.Get(server.URL+URI, "list", url.Values{})
+
+ c.Check(err, IsNil)
+ c.Check(string(result), Equals, expectedResult)
+}
+
+func (suite *GomaasapiTestSuite) TestClientPostSendsRequest(c *C) {
+ URI := "/some/url"
+ expectedResult := "expected:result"
+ client, _ := NewAnonymousClient()
+ fullURI := URI + "?op=list"
+ params := url.Values{"test": {"123"}}
+ server := newSingleServingServer(fullURI, expectedResult, http.StatusOK)
+ defer server.Close()
+
+ result, err := client.Post(server.URL+URI, "list", params)
+
+ c.Check(err, IsNil)
+ c.Check(string(result), Equals, expectedResult)
+ c.Check(*server.requestContent, Equals, "test=123")
+}
+
+func (suite *GomaasapiTestSuite) TestClientPutSendsRequest(c *C) {
+ URI := "/some/url"
+ expectedResult := "expected:result"
+ client, _ := NewAnonymousClient()
+ params := url.Values{"test": {"123"}}
+ server := newSingleServingServer(URI, expectedResult, http.StatusOK)
+ defer server.Close()
+
+ result, err := client.Put(server.URL+URI, params)
+
+ c.Check(err, IsNil)
+ c.Check(string(result), Equals, expectedResult)
+ c.Check(*server.requestContent, Equals, "test=123")
+}
+
+func (suite *GomaasapiTestSuite) TestClientDeleteSendsRequest(c *C) {
+ URI := "/some/url"
+ expectedResult := "expected:result"
+ client, _ := NewAnonymousClient()
+ server := newSingleServingServer(URI, expectedResult, http.StatusOK)
+ defer server.Close()
+
+ err := client.Delete(server.URL + URI)
+
+ c.Check(err, IsNil)
}
func (suite *GomaasapiTestSuite) TestNewAuthenticatedClientParsesApiKey(c *C) {
@@ -65,7 +122,7 @@
client, err := NewAuthenticatedClient(apiKey)
- c.Assert(err, IsNil)
+ c.Check(err, IsNil)
signer := client.Signer.(_PLAINTEXTOAuthSigner)
c.Check(signer.token.ConsumerKey, Equals, consumerKey)
c.Check(signer.token.TokenKey, Equals, tokenKey)
=== modified file 'example/live_example.go'
--- example/live_example.go 2013-01-24 09:16:35 +0000
+++ example/live_example.go 2013-01-25 18:09:19 +0000
@@ -3,15 +3,16 @@
import (
"fmt"
"launchpad.net/gomaasapi"
+ "net/url"
)
var apiKey string
var apiURL string
func init() {
- fmt.Print("Enter apiKey: ")
+ fmt.Print("Enter API key: ")
fmt.Scanf("%s", &apiKey)
- fmt.Print("Enter apiURL: ")
+ fmt.Print("Enter API URL: ")
fmt.Scanf("%s", &apiURL)
}
@@ -21,8 +22,62 @@
panic(err)
}
- server := gomaasapi.Server{apiURL, authClient}
+ server, err := gomaasapi.NewServer(apiURL, *authClient)
+
+ nodeListing := server.SubObject("/nodes/")
+
+ // List nodes.
fmt.Println("Fetching list of nodes...")
- listNodes, _ := server.ListNodes()
- fmt.Printf("Got list of nodes: %s\n", listNodes)
+ listNodeObjects, err := nodeListing.CallGet("list", url.Values{})
+ if err != nil {
+ panic(err)
+ }
+ listNodes, err := listNodeObjects.GetArray()
+ fmt.Printf("Got list of %v nodes\n", len(listNodes))
+ for index, nodeObj := range listNodes {
+ node, _ := nodeObj.GetMAASObject()
+ hostname, _ := node.GetField("hostname")
+ fmt.Printf("Node #%d is named '%v' (%v)\n", index, hostname, node.URL())
+ }
+
+ // Create a node.
+ fmt.Println("Creating a new node...")
+ params := url.Values{"architecture": {"i386/generic"}, "mac_addresses": {"AA:BB:CC:DD:EE:FF"}}
+ newNodeObj, err := nodeListing.CallPost("new", params)
+ if err != nil {
+ panic(err)
+ }
+ newNode, _ := newNodeObj.GetMAASObject()
+ newNodeName, _ := newNode.GetField("hostname")
+ fmt.Printf("New node created: %s (%s)\n", newNodeName, newNode.URL())
+
+ // Update the new node.
+ fmt.Println("Updating the new node...")
+ updateParams := url.Values{"hostname": {"mynewname"}}
+ newNodeObj2, err := newNode.Update(updateParams)
+ if err != nil {
+ panic(err)
+ }
+ newNode2, _ := newNodeObj2.GetMAASObject()
+ newNodeName2, _ := newNode2.GetField("hostname")
+ fmt.Printf("New node updated, now named: %s\n", newNodeName2)
+
+ // Count the nodes.
+ listNodeObjects2, _ := nodeListing.CallGet("list", url.Values{})
+ listNodes2, err := listNodeObjects2.GetArray()
+ fmt.Printf("We've got %v nodes\n", len(listNodes2))
+
+ // Delete the new node.
+ fmt.Println("Deleting the new node...")
+ errDelete := newNode.Delete()
+ if errDelete != nil {
+ panic(errDelete)
+ }
+
+ // Count the nodes.
+ listNodeObjects3, _ := nodeListing.CallGet("list", url.Values{})
+ listNodes3, err := listNodeObjects3.GetArray()
+ fmt.Printf("We've got %v nodes\n", len(listNodes3))
+
+ fmt.Println("All done.")
}
=== modified file 'jsonobject.go'
--- jsonobject.go 2013-01-25 11:37:56 +0000
+++ jsonobject.go 2013-01-25 18:09:19 +0000
@@ -66,7 +66,7 @@
// JSONObject (with the appropriate implementation of course).
// This function is recursive. Maps and arrays are deep-copied, with each
// individual value being converted to a JSONObject type.
-func maasify(client Client, value interface{}) JSONObject {
+func maasify(client Client, baseURL string, value interface{}) JSONObject {
if value == nil {
return nil
}
@@ -81,19 +81,19 @@
original := value.(map[string]interface{})
result := make(map[string]JSONObject, len(original))
for key, value := range original {
- result[key] = maasify(client, value)
+ result[key] = maasify(client, baseURL, value)
}
if _, ok := result[resource_uri]; ok {
// If the map contains "resource-uri", we can treat
// it as a MAAS object.
- return jsonMAASObject{result, client}
+ return jsonMAASObject{result, client, baseURL}
}
return jsonMap(result)
case []interface{}:
original := value.([]interface{})
result := make([]JSONObject, len(original))
for index, value := range original {
- result[index] = maasify(client, value)
+ result[index] = maasify(client, baseURL, value)
}
return jsonArray(result)
case bool:
@@ -104,13 +104,13 @@
}
// Parse a JSON blob into a JSONObject.
-func Parse(client Client, input []byte) (JSONObject, error) {
+func Parse(client Client, baseURL string, input []byte) (JSONObject, error) {
var obj interface{}
err := json.Unmarshal(input, &obj)
if err != nil {
return nil, err
}
- return maasify(client, obj), nil
+ return maasify(client, baseURL, obj), nil
}
// Return error value for failed type conversion.
=== modified file 'jsonobject_test.go'
--- jsonobject_test.go 2013-01-25 11:37:26 +0000
+++ jsonobject_test.go 2013-01-25 18:09:19 +0000
@@ -9,37 +9,37 @@
// maasify() converts nil.
func (suite *GomaasapiTestSuite) TestMaasifyConvertsNil(c *C) {
- c.Check(maasify(Client{}, nil), Equals, nil)
+ c.Check(maasify(Client{}, "", nil), Equals, nil)
}
// maasify() converts strings.
func (suite *GomaasapiTestSuite) TestMaasifyConvertsString(c *C) {
const text = "Hello"
- c.Check(string(maasify(Client{}, text).(jsonString)), Equals, text)
+ c.Check(string(maasify(Client{}, "", text).(jsonString)), Equals, text)
}
// maasify() converts float64 numbers.
func (suite *GomaasapiTestSuite) TestMaasifyConvertsNumber(c *C) {
const number = 3.1415926535
- c.Check(float64(maasify(Client{}, number).(jsonFloat64)), Equals, number)
+ c.Check(float64(maasify(Client{}, "", number).(jsonFloat64)), Equals, number)
}
// Any number converts to float64, even integers.
func (suite *GomaasapiTestSuite) TestMaasifyConvertsIntegralNumber(c *C) {
const number = 1
- c.Check(float64(maasify(Client{}, number).(jsonFloat64)), Equals, float64(number))
+ c.Check(float64(maasify(Client{}, "", number).(jsonFloat64)), Equals, float64(number))
}
// maasify() converts array slices.
func (suite *GomaasapiTestSuite) TestMaasifyConvertsArray(c *C) {
original := []interface{}{3.0, 2.0, 1.0}
- output := maasify(Client{}, original).(jsonArray)
+ output := maasify(Client{}, "", original).(jsonArray)
c.Check(len(output), Equals, len(original))
}
// When maasify() converts an array slice, the result contains JSONObjects.
func (suite *GomaasapiTestSuite) TestMaasifyArrayContainsJSONObjects(c *C) {
- arr := maasify(Client{}, []interface{}{9.9}).(jsonArray)
+ arr := maasify(Client{}, "", []interface{}{9.9}).(jsonArray)
var entry JSONObject
entry = arr[0]
c.Check((float64)(entry.(jsonFloat64)), Equals, 9.9)
@@ -48,13 +48,13 @@
// maasify() converts maps.
func (suite *GomaasapiTestSuite) TestMaasifyConvertsMap(c *C) {
original := map[string]interface{}{"1": "one", "2": "two", "3": "three"}
- output := maasify(Client{}, original).(jsonMap)
+ output := maasify(Client{}, "", original).(jsonMap)
c.Check(len(output), Equals, len(original))
}
// When maasify() converts a map, the result contains JSONObjects.
func (suite *GomaasapiTestSuite) TestMaasifyMapContainsJSONObjects(c *C) {
- mp := maasify(Client{}, map[string]interface{}{"key": "value"}).(jsonMap)
+ mp := maasify(Client{}, "", map[string]interface{}{"key": "value"}).(jsonMap)
var entry JSONObject
entry = mp["key"]
c.Check((string)(entry.(jsonString)), Equals, "value")
@@ -66,59 +66,67 @@
"resource_uri": "http://example.com/foo",
"size": "3",
}
- output := maasify(Client{}, original).(jsonMAASObject)
+ output := maasify(Client{}, "", original).(jsonMAASObject)
c.Check(len(output.jsonMap), Equals, len(original))
c.Check((string)(output.jsonMap["size"].(jsonString)), Equals, "3")
}
-// maasify() passes its Client to a MAASObject it creates.
-func (suite *GomaasapiTestSuite) TestMaasifyPassesClientToMAASObject(c *C) {
+// maasify() passes its info (client and baseURL) to a MAASObject it creates.
+func (suite *GomaasapiTestSuite) TestMaasifyPassesInfoToMAASObject(c *C) {
client := Client{}
- original := map[string]interface{}{"resource_uri": "http://example.com/foo"}
- output := maasify(client, original).(jsonMAASObject)
+ original := map[string]interface{}{"resource_uri": "/foo"}
+ baseURL := "http://example.com"
+ output := maasify(client, baseURL, original).(jsonMAASObject)
c.Check(output.client, Equals, client)
+ c.Check(output.baseURL, Equals, baseURL)
}
-// maasify() passes its Client into an array of MAASObjects it creates.
-func (suite *GomaasapiTestSuite) TestMaasifyPassesClientIntoArray(c *C) {
+// maasify() passes its info (client and baseURL) into an array of MAASObjects it creates.
+func (suite *GomaasapiTestSuite) TestMaasifyPassesInfoIntoArray(c *C) {
client := Client{}
- obj := map[string]interface{}{"resource_uri": "http://example.com/foo"}
+ obj := map[string]interface{}{"resource_uri": "/foo"}
+ baseURL := "http://example.com"
list := []interface{}{obj}
- output := maasify(client, list).(jsonArray)
+ output := maasify(client, baseURL, list).(jsonArray)
c.Check(output[0].(jsonMAASObject).client, Equals, client)
+ c.Check(output[0].(jsonMAASObject).baseURL, Equals, baseURL)
}
-// maasify() passes its Client into a map of MAASObjects it creates.
-func (suite *GomaasapiTestSuite) TestMaasifyPassesClientIntoMap(c *C) {
+// maasify() passes its info (client and baseURL) into a map of MAASObjects it creates.
+func (suite *GomaasapiTestSuite) TestMaasifyPassesInfoIntoMap(c *C) {
client := Client{}
- obj := map[string]interface{}{"resource_uri": "http://example.com/foo"}
+ obj := map[string]interface{}{"resource_uri": "/foo"}
+ baseURL := "http://example.com"
mp := map[string]interface{}{"key": obj}
- output := maasify(client, mp).(jsonMap)
+ output := maasify(client, baseURL, mp).(jsonMap)
c.Check(output["key"].(jsonMAASObject).client, Equals, client)
+ c.Check(output["key"].(jsonMAASObject).baseURL, Equals, baseURL)
}
-// maasify() passes its Client all the way down into any MAASObjects in the
-// object structure it creates.
-func (suite *GomaasapiTestSuite) TestMaasifyPassesClientAllTheWay(c *C) {
+// maasify() passes its info (client and baseURL) all the way down into any
+// MAASObjects in the object structure it creates.
+func (suite *GomaasapiTestSuite) TestMaasifyPassesInfoAllTheWay(c *C) {
client := Client{}
- obj := map[string]interface{}{"resource_uri": "http://example.com/foo"}
+ obj := map[string]interface{}{"resource_uri": "/foo"}
+ baseURL := "http://example.com"
mp := map[string]interface{}{"key": obj}
list := []interface{}{mp}
- output := maasify(client, list).(jsonArray)
+ output := maasify(client, baseURL, list).(jsonArray)
maasobj := output[0].(jsonMap)["key"]
c.Check(maasobj.(jsonMAASObject).client, Equals, client)
+ c.Check(maasobj.(jsonMAASObject).baseURL, Equals, baseURL)
}
// maasify() converts Booleans.
func (suite *GomaasapiTestSuite) TestMaasifyConvertsBool(c *C) {
- c.Check(bool(maasify(Client{}, true).(jsonBool)), Equals, true)
- c.Check(bool(maasify(Client{}, false).(jsonBool)), Equals, false)
+ c.Check(bool(maasify(Client{}, "", true).(jsonBool)), Equals, true)
+ c.Check(bool(maasify(Client{}, "", false).(jsonBool)), Equals, false)
}
// Parse takes you from a JSON blob to a JSONObject.
func (suite *GomaasapiTestSuite) TestParseMaasifiesJSONBlob(c *C) {
blob := []byte("[12]")
- obj, err := Parse(Client{}, blob)
+ obj, err := Parse(Client{}, "", blob)
c.Check(err, IsNil)
c.Check(float64(obj.(jsonArray)[0].(jsonFloat64)), Equals, 12.0)
}
=== modified file 'maasobject.go'
--- maasobject.go 2013-01-25 11:37:56 +0000
+++ maasobject.go 2013-01-25 18:09:19 +0000
@@ -16,12 +16,16 @@
type MAASObject interface {
JSONObject
+ // Utility method to extract a string field from this MAAS object.
+ GetField(name string) (string, error)
// Resource URI for this MAAS object.
URL() string
+ // Retrieve the MAAS object located at thisObject.URL()+name.
+ SubObject(name string) MAASObject
// Retrieve this MAAS object.
Get() (MAASObject, error)
// Write this MAAS object.
- Post(params url.Values) (MAASObject, error)
+ Post(params url.Values) (JSONObject, error)
// Update this MAAS object with the given values.
Update(params url.Values) (MAASObject, error)
// Delete this MAAS object.
@@ -39,7 +43,8 @@
// jsonMAASObject implements both JSONObject and MAASObject.
type jsonMAASObject struct {
jsonMap
- client Client
+ client Client
+ baseURL string
}
var _ JSONObject = (*jsonMAASObject)(nil)
@@ -56,38 +61,85 @@
// MAASObject implementation for jsonMAASObject.
-func (obj jsonMAASObject) URL() string {
+func (obj jsonMAASObject) GetField(name string) (string, error) {
+ return obj.jsonMap[name].GetString()
+}
+
+func (obj jsonMAASObject) _URI() (string, error) {
contents, err := obj.GetMap()
if err != nil {
panic("Unexpected failure converting jsonMAASObject to maasMap.")
}
- url, err := contents[resource_uri].GetString()
- if err != nil {
- panic("Unexpected failure reading jsonMAASObject's URL.")
- }
- return url
+ return contents[resource_uri].GetString()
+}
+
+func (obj jsonMAASObject) URL() string {
+ uri, err := obj._URI()
+ if err != nil {
+ panic("Unexpected failure reading jsonMAASObject's URL.")
+ }
+ return obj.baseURL + uri
+}
+
+func (obj jsonMAASObject) SubObject(name string) MAASObject {
+ uri, err := obj._URI()
+ if err != nil {
+ panic("Unexpected failure reading jsonMAASObject's URL.")
+ }
+ input := map[string]JSONObject{resource_uri: jsonString(uri + name)}
+ return jsonMAASObject{jsonMap: jsonMap(input), client: obj.client, baseURL: obj.baseURL}
}
var NotImplemented = errors.New("Not implemented")
func (obj jsonMAASObject) Get() (MAASObject, error) {
- return jsonMAASObject{}, NotImplemented
+ result, err := obj.client.Get(obj.URL(), "", url.Values{})
+ if err != nil {
+ return nil, err
+ }
+ jsonObj, err := Parse(obj.client, obj.baseURL, result)
+ if err != nil {
+ return nil, err
+ }
+ return jsonObj.GetMAASObject()
}
-func (obj jsonMAASObject) Post(params url.Values) (MAASObject, error) {
- return jsonMAASObject{}, NotImplemented
+func (obj jsonMAASObject) Post(params url.Values) (JSONObject, error) {
+ result, err := obj.client.Post(obj.URL(), "", params)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(obj.client, obj.baseURL, result)
}
func (obj jsonMAASObject) Update(params url.Values) (MAASObject, error) {
- return jsonMAASObject{}, NotImplemented
+ result, err := obj.client.Put(obj.URL(), params)
+ if err != nil {
+ return nil, err
+ }
+ jsonObj, err := Parse(obj.client, obj.baseURL, result)
+ if err != nil {
+ return nil, err
+ }
+ return jsonObj.GetMAASObject()
}
-func (obj jsonMAASObject) Delete() error { return NotImplemented }
+func (obj jsonMAASObject) Delete() error {
+ return obj.client.Delete(obj.URL())
+}
func (obj jsonMAASObject) CallGet(operation string, params url.Values) (JSONObject, error) {
- return nil, NotImplemented
+ result, err := obj.client.Get(obj.URL(), operation, params)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(obj.client, obj.baseURL, result)
}
func (obj jsonMAASObject) CallPost(operation string, params url.Values) (JSONObject, error) {
- return nil, NotImplemented
+ result, err := obj.client.Post(obj.URL(), operation, params)
+ if err != nil {
+ return nil, err
+ }
+ return Parse(obj.client, obj.baseURL, result)
}
=== modified file 'maasobject_test.go'
--- maasobject_test.go 2013-01-25 11:06:31 +0000
+++ maasobject_test.go 2013-01-25 18:09:19 +0000
@@ -50,3 +50,16 @@
obj := jsonMAASObject{jsonMap: jsonMap(input)}
c.Check(obj.URL(), Equals, uri)
}
+
+func (suite *GomaasapiTestSuite) TestGetField(c *C) {
+ uri := "http://example.com/a/resource"
+ fieldName := "field name"
+ fieldValue := "a value"
+ input := map[string]JSONObject{
+ resource_uri: jsonString(uri), fieldName: jsonString(fieldValue),
+ }
+ obj := jsonMAASObject{jsonMap: jsonMap(input)}
+ value, err := obj.GetField(fieldName)
+ c.Check(err, IsNil)
+ c.Check(value, Equals, fieldValue)
+}
=== modified file 'server.go'
--- server.go 2013-01-25 11:37:26 +0000
+++ server.go 2013-01-25 18:09:19 +0000
@@ -4,25 +4,17 @@
package gomaasapi
import (
+ "fmt"
"net/url"
)
-type Server struct {
- URL string
- Client *Client
-}
-
-func (server *Server) ListNodes() ([]JSONObject, error) {
- listURL := server.URL + "/nodes/"
- params := url.Values{}
- params.Add("op", "list")
- result, err := server.Client.Get(listURL, params)
- if err != nil {
- return nil, err
- }
- jsonobj, err := Parse(*server.Client, result)
- if err != nil {
- return nil, err
- }
- return jsonobj.GetArray()
+func NewServer(URL string, client Client) (MAASObject, error) {
+ parsed, err := url.Parse(URL)
+ if err != nil {
+ return nil, err
+ }
+ baseURL := fmt.Sprintf("%s://%s", parsed.Scheme, parsed.Host)
+ resourceURI := parsed.Path
+ input := map[string]JSONObject{resource_uri: jsonString(resourceURI)}
+ return jsonMAASObject{jsonMap: jsonMap(input), client: client, baseURL: baseURL}, nil
}
=== modified file 'server_test.go'
--- server_test.go 2013-01-25 11:37:26 +0000
+++ server_test.go 2013-01-25 18:09:19 +0000
@@ -5,36 +5,16 @@
import (
. "launchpad.net/gocheck"
- "net/http"
)
-func (suite *GomaasapiTestSuite) TestServerListNodesReturnsMAASObject(c *C) {
- URL := "/nodes/?op=list"
- blob := `[{"resource_uri": "/obj1"}, {"resource_uri": "/obj2"}]`
- testServer := newSingleServingServer(URL, blob, http.StatusOK)
- defer testServer.Close()
- client, _ := NewAnonymousClient()
- server := Server{testServer.URL, client}
-
- result, err := server.ListNodes()
-
- c.Assert(err, IsNil)
- c.Check(result, Not(IsNil))
- c.Check(len(result), Equals, 2)
- obj1, err := result[0].GetMAASObject()
- c.Assert(err, IsNil)
- c.Check(obj1.URL(), Equals, "/obj1")
-}
-
-func (suite *GomaasapiTestSuite) TestServerListNodesReturnsServerError(c *C) {
- URL := "/nodes/?op=list"
- expectedResult := "expected:result"
- testServer := newSingleServingServer(URL, expectedResult, http.StatusBadRequest)
- defer testServer.Close()
- client, _ := NewAnonymousClient()
- server := Server{testServer.URL, client}
-
- _, err := server.ListNodes()
-
- c.Assert(err, ErrorMatches, "Error requesting the MAAS server: 400 Bad Request.*")
+func (suite *GomaasapiTestSuite) TestServerParsesURL(c *C) {
+ server, err := NewServer("https://server.com:888/path/to/api", Client{})
+
+ c.Check(err, IsNil)
+ c.Check(server.URL(), Equals, "https://server.com:888/path/to/api")
+ jsonObj := server.(jsonMAASObject)
+ uri, err := jsonObj._URI()
+ c.Check(err, IsNil)
+ c.Check(uri, Equals, "/path/to/api")
+ c.Check(jsonObj.baseURL, Equals, "https://server.com:888")
}
=== modified file 'testing.go'
--- testing.go 2013-01-25 08:39:47 +0000
+++ testing.go 2013-01-25 18:09:19 +0000
@@ -33,7 +33,8 @@
requestContent = string(res)
requestHeader = request.Header
if request.URL.String() != uri {
- http.Error(writer, "404 page not found", http.StatusNotFound)
+ errorMsg := fmt.Sprintf("404 page not found (expected '%v', got '%v').", uri, request.URL.String())
+ http.Error(writer, errorMsg, http.StatusNotFound)
} else {
writer.WriteHeader(code)
fmt.Fprint(writer, response)
Follow ups