func (c *Client) ClusterList() (*api.ClusterListResponse, error) { // Create request req, err := http.NewRequest("GET", c.host+"/clusters", nil) if err != nil { return nil, err } // Set token err = c.setToken(req) if err != nil { return nil, err } // Get info r, err := c.do(req) if err != nil { return nil, err } if r.StatusCode != http.StatusOK { return nil, utils.GetErrorFromResponse(r) } // Read JSON response var clusters api.ClusterListResponse err = utils.GetJsonFromResponse(r, &clusters) if err != nil { return nil, err } return &clusters, nil }
func (c *Client) ClusterCreate() (*api.ClusterInfoResponse, error) { // Create a request req, err := http.NewRequest("POST", c.host+"/clusters", bytes.NewBuffer([]byte(`{}`))) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") // Set token err = c.setToken(req) if err != nil { return nil, err } // Send request r, err := c.do(req) if err != nil { return nil, err } if r.StatusCode != http.StatusCreated { return nil, utils.GetErrorFromResponse(r) } // Read JSON response var cluster api.ClusterInfoResponse err = utils.GetJsonFromResponse(r, &cluster) r.Body.Close() if err != nil { return nil, err } return &cluster, nil }
func (c *Client) VolumeInfo(id string) (*api.VolumeInfoResponse, error) { // Create request req, err := http.NewRequest("GET", c.host+"/volumes/"+id, nil) if err != nil { return nil, err } // Set token err = c.setToken(req) if err != nil { return nil, err } // Get info r, err := c.do(req) if err != nil { return nil, err } if r.StatusCode != http.StatusOK { return nil, utils.GetErrorFromResponse(r) } // Read JSON response var volume api.VolumeInfoResponse err = utils.GetJsonFromResponse(r, &volume) r.Body.Close() if err != nil { return nil, err } return &volume, nil }
func TestVolumeListEmpty(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Get volumes, there should be none r, err := http.Get(ts.URL + "/volumes") tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg api.VolumeListResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) tests.Assert(t, len(msg.Volumes) == 0) }
func TestVolumeList(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create some volumes numvolumes := 1000 err := app.db.Update(func(tx *bolt.Tx) error { for i := 0; i < numvolumes; i++ { v := createSampleVolumeEntry(100) err := v.Save(tx) if err != nil { return err } } return nil }) tests.Assert(t, err == nil) // Get volumes, there should be none r, err := http.Get(ts.URL + "/volumes") tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg api.VolumeListResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) tests.Assert(t, len(msg.Volumes) == numvolumes) // Check that all the volumes are in the database err = app.db.View(func(tx *bolt.Tx) error { for _, id := range msg.Volumes { _, err := NewVolumeEntryFromId(tx, id) if err != nil { return err } } return nil }) tests.Assert(t, err == nil) }
func TestVolumeInfo(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Setup database err := setupSampleDbWithTopology(app, 1, // clusters 10, // nodes_per_cluster 10, // devices_per_node, 5*TB, // disksize) ) tests.Assert(t, err == nil) // Create a volume req := &api.VolumeCreateRequest{} req.Size = 100 req.Durability.Type = api.DurabilityEC v := NewVolumeEntryFromRequest(req) tests.Assert(t, v != nil) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Now that we have some data in the database, we can // make a request for the clutser list r, err := http.Get(ts.URL + "/volumes/" + v.Info.Id) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg api.VolumeInfoResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) tests.Assert(t, msg.Id == v.Info.Id) tests.Assert(t, msg.Cluster == v.Info.Cluster) tests.Assert(t, msg.Name == v.Info.Name) tests.Assert(t, msg.Size == v.Info.Size) tests.Assert(t, reflect.DeepEqual(msg.Durability, v.Info.Durability)) tests.Assert(t, reflect.DeepEqual(msg.Snapshot, v.Info.Snapshot)) for _, brick := range msg.Bricks { tests.Assert(t, utils.SortedStringHas(v.Bricks, brick.Id)) } }
func (c *Client) VolumeExpand(id string, request *api.VolumeExpandRequest) ( *api.VolumeInfoResponse, error) { // Marshal request to JSON buffer, err := json.Marshal(request) if err != nil { return nil, err } // Create a request req, err := http.NewRequest("POST", c.host+"/volumes/"+id+"/expand", bytes.NewBuffer(buffer)) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") // Set token err = c.setToken(req) if err != nil { return nil, err } // Send request r, err := c.do(req) if err != nil { return nil, err } if r.StatusCode != http.StatusAccepted { return nil, utils.GetErrorFromResponse(r) } // Wait for response r, err = c.waitForResponseWithTimer(r, time.Second) if err != nil { return nil, err } if r.StatusCode != http.StatusOK { return nil, utils.GetErrorFromResponse(r) } // Read JSON response var volume api.VolumeInfoResponse err = utils.GetJsonFromResponse(r, &volume) r.Body.Close() if err != nil { return nil, err } return &volume, nil }
func (c *Client) NodeAdd(request *api.NodeAddRequest) (*api.NodeInfoResponse, error) { // Marshal request to JSON buffer, err := json.Marshal(request) if err != nil { return nil, err } // Create a request req, err := http.NewRequest("POST", c.host+"/nodes", bytes.NewBuffer(buffer)) if err != nil { return nil, err } req.Header.Set("Content-Type", "application/json") // Set token err = c.setToken(req) if err != nil { return nil, err } // Send request r, err := c.do(req) if err != nil { return nil, err } if r.StatusCode != http.StatusAccepted { return nil, utils.GetErrorFromResponse(r) } // Wait for response r, err = c.waitForResponseWithTimer(r, time.Millisecond*250) if err != nil { return nil, err } if r.StatusCode != http.StatusOK { return nil, utils.GetErrorFromResponse(r) } // Read JSON response var node api.NodeInfoResponse err = utils.GetJsonFromResponse(r, &node) r.Body.Close() if err != nil { return nil, err } return &node, nil }
func TestClusterCreate(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // ClusterCreate JSON Request request := []byte(`{ }`) // Post nothing r, err := http.Post(ts.URL+"/clusters", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusCreated) // Read JSON var msg api.ClusterInfoResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) // Test JSON tests.Assert(t, len(msg.Nodes) == 0) tests.Assert(t, len(msg.Volumes) == 0) // Check that the data on the database is recorded correctly var entry ClusterEntry err = app.db.View(func(tx *bolt.Tx) error { return entry.Unmarshal( tx.Bucket([]byte(BOLTDB_BUCKET_CLUSTER)). Get([]byte(msg.Id))) }) tests.Assert(t, err == nil) // Make sure they entries are euqal tests.Assert(t, entry.Info.Id == msg.Id) tests.Assert(t, len(entry.Info.Volumes) == 0) tests.Assert(t, len(entry.Info.Nodes) == 0) }
func TestDeviceInfo(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create a device to save in the db device := NewDeviceEntry() device.Info.Id = "abc" device.Info.Name = "/dev/fake1" device.NodeId = "def" device.StorageSet(10000) device.StorageAllocate(1000) // Save device in the db err := app.db.Update(func(tx *bolt.Tx) error { return device.Save(tx) }) tests.Assert(t, err == nil) // Get device information r, err := http.Get(ts.URL + "/devices/" + device.Info.Id) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") var info api.DeviceInfoResponse err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, info.Id == device.Info.Id) tests.Assert(t, info.Name == device.Info.Name) tests.Assert(t, info.State == "online") tests.Assert(t, info.Storage.Free == device.Info.Storage.Free) tests.Assert(t, info.Storage.Used == device.Info.Storage.Used) tests.Assert(t, info.Storage.Total == device.Info.Storage.Total) }
func TestNodeInfo(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create a node to save in the db node := NewNodeEntry() node.Info.Id = "abc" node.Info.ClusterId = "123" node.Info.Hostnames.Manage = sort.StringSlice{"manage.system"} node.Info.Hostnames.Storage = sort.StringSlice{"storage.system"} node.Info.Zone = 10 // Save node in the db err := app.db.Update(func(tx *bolt.Tx) error { return node.Save(tx) }) tests.Assert(t, err == nil) // Get unknown node id r, err := http.Get(ts.URL + "/nodes/" + node.Info.Id) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") var info api.NodeInfoResponse err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, info.Id == node.Info.Id) tests.Assert(t, info.Hostnames.Manage[0] == node.Info.Hostnames.Manage[0]) tests.Assert(t, len(info.Hostnames.Manage) == len(node.Info.Hostnames.Manage)) tests.Assert(t, info.Hostnames.Storage[0] == node.Info.Hostnames.Storage[0]) tests.Assert(t, len(info.Hostnames.Storage) == len(node.Info.Hostnames.Storage)) tests.Assert(t, info.Zone == node.Info.Zone) }
func TestVolumeCreate(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Setup database err := setupSampleDbWithTopology(app, 1, // clusters 10, // nodes_per_cluster 10, // devices_per_node, 5*TB, // disksize) ) tests.Assert(t, err == nil) // VolumeCreate using default durability request := []byte(`{ "size" : 100 }`) // Send request r, err := http.Post(ts.URL+"/volumes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err := r.Location() tests.Assert(t, err == nil) // Query queue until finished var info api.VolumeInfoResponse for { r, err = http.Get(location.String()) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) if r.ContentLength <= 0 { time.Sleep(time.Millisecond * 10) continue } else { // Should have node information here tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, err == nil) break } } tests.Assert(t, info.Id != "") tests.Assert(t, info.Cluster != "") tests.Assert(t, len(info.Bricks) == 2) // Only two 50GB bricks needed tests.Assert(t, info.Bricks[0].Size == 50*GB) tests.Assert(t, info.Bricks[1].Size == 50*GB) tests.Assert(t, info.Name == "vol_"+info.Id) tests.Assert(t, info.Snapshot.Enable == false) tests.Assert(t, info.Snapshot.Factor == 1) tests.Assert(t, info.Durability.Type == api.DurabilityDistributeOnly) }
func TestVolumeExpand(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create a cluster err := setupSampleDbWithTopology(app, 1, // clusters 10, // nodes_per_cluster 10, // devices_per_node, 5*TB, // disksize) ) tests.Assert(t, err == nil) // Create a volume v := createSampleVolumeEntry(100) tests.Assert(t, v != nil) err = v.Create(app.db, app.executor, app.allocator) tests.Assert(t, err == nil) // Keep a copy vc := &VolumeEntry{} *vc = *v // JSON Request request := []byte(`{ "expand_size" : 1000 }`) // Send request r, err := http.Post(ts.URL+"/volumes/"+v.Info.Id+"/expand", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err := r.Location() tests.Assert(t, err == nil) // Query queue until finished var info api.VolumeInfoResponse for { r, err := http.Get(location.String()) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) if r.Header.Get("X-Pending") == "true" { time.Sleep(time.Millisecond * 10) continue } else { err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, err == nil) break } } tests.Assert(t, info.Size == 100+1000) tests.Assert(t, len(vc.Bricks) < len(info.Bricks)) }
func TestDeviceState(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create mock allocator mockAllocator := NewMockAllocator(app.db) app.allocator = mockAllocator // Create a client c := client.NewClientNoAuth(ts.URL) tests.Assert(t, c != nil) // Create Cluster cluster, err := c.ClusterCreate() tests.Assert(t, err == nil) // Create Node nodeReq := &api.NodeAddRequest{ Zone: 1, ClusterId: cluster.Id, } nodeReq.Hostnames.Manage = sort.StringSlice{"manage.host"} nodeReq.Hostnames.Storage = sort.StringSlice{"storage.host"} node, err := c.NodeAdd(nodeReq) tests.Assert(t, err == nil) // Add device deviceReq := &api.DeviceAddRequest{} deviceReq.Name = "/dev/fake1" deviceReq.NodeId = node.Id err = c.DeviceAdd(deviceReq) tests.Assert(t, err == nil) // Get node information again node, err = c.NodeInfo(node.Id) tests.Assert(t, err == nil) // Get device information deviceId := node.DevicesInfo[0].Id device, err := c.DeviceInfo(deviceId) tests.Assert(t, err == nil) // Get info deviceInfo, err := c.DeviceInfo(device.Id) tests.Assert(t, err == nil) tests.Assert(t, deviceInfo.State == "online") // Check that the device is in the ring tests.Assert(t, len(mockAllocator.clustermap[cluster.Id]) == 1) tests.Assert(t, mockAllocator.clustermap[cluster.Id][0] == device.Id) // Set offline request := []byte(`{ "state" : "offline" }`) r, err := http.Post(ts.URL+"/devices/"+device.Id+"/state", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) // Check it was removed from the ring tests.Assert(t, len(mockAllocator.clustermap[cluster.Id]) == 0) // Get Device Info r, err = http.Get(ts.URL + "/devices/" + device.Id) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") var info api.DeviceInfoResponse err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, info.Id == device.Id) tests.Assert(t, info.Name == device.Name) tests.Assert(t, info.State == "offline") tests.Assert(t, info.Storage.Free == device.Storage.Free) tests.Assert(t, info.Storage.Used == device.Storage.Used) tests.Assert(t, info.Storage.Total == device.Storage.Total) // Set online again request = []byte(`{ "state" : "online" }`) r, err = http.Post(ts.URL+"/devices/"+device.Id+"/state", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) // Check that the device is in the ring tests.Assert(t, len(mockAllocator.clustermap[cluster.Id]) == 1) tests.Assert(t, mockAllocator.clustermap[cluster.Id][0] == device.Id) // Get Device Info r, err = http.Get(ts.URL + "/devices/" + device.Id) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, info.Id == device.Id) tests.Assert(t, info.Name == device.Name) tests.Assert(t, info.State == "online") tests.Assert(t, info.Storage.Free == device.Storage.Free) tests.Assert(t, info.Storage.Used == device.Storage.Used) tests.Assert(t, info.Storage.Total == device.Storage.Total) // Set to unknown state request = []byte(`{ "state" : "blah" }`) r, err = http.Post(ts.URL+"/devices/"+device.Id+"/state", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusBadRequest) // Check that the device is still in the ring tests.Assert(t, len(mockAllocator.clustermap[cluster.Id]) == 1) tests.Assert(t, mockAllocator.clustermap[cluster.Id][0] == device.Id) // Make sure the state did not change r, err = http.Get(ts.URL + "/devices/" + device.Id) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") err = utils.GetJsonFromResponse(r, &info) tests.Assert(t, info.Id == device.Id) tests.Assert(t, info.Name == device.Name) tests.Assert(t, info.State == "online") tests.Assert(t, info.Storage.Free == device.Storage.Free) tests.Assert(t, info.Storage.Used == device.Storage.Used) tests.Assert(t, info.Storage.Total == device.Storage.Total) }
func TestPeerProbe(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // ClusterCreate JSON Request request := []byte(`{ }`) // Post nothing r, err := http.Post(ts.URL+"/clusters", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusCreated) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read cluster information var clusterinfo api.ClusterInfoResponse err = utils.GetJsonFromResponse(r, &clusterinfo) tests.Assert(t, err == nil) // Override mock to check if the peer function was called probe_called := false app.xo.MockPeerProbe = func(exec_host, newnode string) error { probe_called = true return nil } // Create node on this cluster request = []byte(`{ "cluster" : "` + clusterinfo.Id + `", "hostnames" : { "storage" : [ "storage0.hostname.com" ], "manage" : [ "manage0.hostname.com" ] }, "zone" : 1 }`) // Create node r, err = http.Post(ts.URL+"/nodes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err := r.Location() tests.Assert(t, err == nil) // Query queue until finished for { r, err = http.Get(location.String()) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) if r.ContentLength <= 0 { time.Sleep(time.Millisecond * 10) continue } else { // Should have node information here tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") tests.Assert(t, err == nil) break } } tests.Assert(t, probe_called == false) // Now add another and check that probe was called request = []byte(`{ "cluster" : "` + clusterinfo.Id + `", "hostnames" : { "storage" : [ "storage1.hostname.com" ], "manage" : [ "manage1.hostname.com" ] }, "zone" : 1 }`) // Create node r, err = http.Post(ts.URL+"/nodes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err = r.Location() tests.Assert(t, err == nil) // Query queue until finished for { r, err = http.Get(location.String()) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) if r.ContentLength <= 0 { time.Sleep(time.Millisecond * 10) continue } else { // Should have node information here tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") tests.Assert(t, err == nil) break } } tests.Assert(t, probe_called == true) }
func TestNodeAddDelete(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // ClusterCreate JSON Request request := []byte(`{ }`) // Post nothing r, err := http.Post(ts.URL+"/clusters", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusCreated) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read cluster information var clusterinfo api.ClusterInfoResponse err = utils.GetJsonFromResponse(r, &clusterinfo) tests.Assert(t, err == nil) // Create node on this cluster request = []byte(`{ "cluster" : "` + clusterinfo.Id + `", "hostnames" : { "storage" : [ "storage.hostname.com" ], "manage" : [ "manage.hostname.com" ] }, "zone" : 1 }`) // Create node r, err = http.Post(ts.URL+"/nodes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err := r.Location() tests.Assert(t, err == nil) // Query queue until finished var node api.NodeInfoResponse for { r, err = http.Get(location.String()) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) if r.ContentLength <= 0 { time.Sleep(time.Millisecond * 10) continue } else { // Should have node information here tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") err = utils.GetJsonFromResponse(r, &node) tests.Assert(t, err == nil) break } } tests.Assert(t, len(node.Id) > 0) tests.Assert(t, len(node.Hostnames.Manage) == 1) tests.Assert(t, len(node.Hostnames.Storage) == 1) tests.Assert(t, node.Hostnames.Manage[0] == "manage.hostname.com") tests.Assert(t, node.Hostnames.Storage[0] == "storage.hostname.com") tests.Assert(t, node.Zone == 1) tests.Assert(t, node.ClusterId == clusterinfo.Id) tests.Assert(t, len(node.DevicesInfo) == 0) // Check that the node has registered err = app.db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(BOLTDB_BUCKET_NODE)) tests.Assert(t, b != nil) val := b.Get([]byte("STORAGE" + node.Hostnames.Storage[0])) tests.Assert(t, string(val) == node.Id) val = b.Get([]byte("MANAGE" + node.Hostnames.Manage[0])) tests.Assert(t, string(val) == node.Id) return nil }) tests.Assert(t, err == nil) //---- OK, now it should have been registered // now let's add it again // It should return a conflict r, err = http.Post(ts.URL+"/nodes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusConflict) tests.Assert(t, err == nil) // Check Cluster has node r, err = http.Get(ts.URL + "/clusters/" + clusterinfo.Id) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") err = utils.GetJsonFromResponse(r, &clusterinfo) tests.Assert(t, len(clusterinfo.Nodes) == 1) tests.Assert(t, clusterinfo.Nodes[0] == node.Id) // Check the data is in the database correctly var entry *NodeEntry err = app.db.View(func(tx *bolt.Tx) error { entry, err = NewNodeEntryFromId(tx, node.Id) return err }) tests.Assert(t, err == nil) tests.Assert(t, entry != nil) tests.Assert(t, entry.Info.Id == node.Id) tests.Assert(t, len(entry.Info.Hostnames.Manage) == 1) tests.Assert(t, len(entry.Info.Hostnames.Storage) == 1) tests.Assert(t, entry.Info.Hostnames.Manage[0] == node.Hostnames.Manage[0]) tests.Assert(t, entry.Info.Hostnames.Storage[0] == node.Hostnames.Storage[0]) tests.Assert(t, len(entry.Devices) == 0) // Add some devices to check if delete conflict works err = app.db.Update(func(tx *bolt.Tx) error { entry, err = NewNodeEntryFromId(tx, node.Id) if err != nil { return err } entry.DeviceAdd("123") entry.DeviceAdd("456") return entry.Save(tx) }) tests.Assert(t, err == nil) // Now delete node and check for conflict req, err := http.NewRequest("DELETE", ts.URL+"/nodes/"+node.Id, nil) tests.Assert(t, err == nil) r, err = http.DefaultClient.Do(req) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusConflict) // Check that nothing has changed in the db var cluster *ClusterEntry err = app.db.View(func(tx *bolt.Tx) error { entry, err = NewNodeEntryFromId(tx, node.Id) if err != nil { return err } cluster, err = NewClusterEntryFromId(tx, entry.Info.ClusterId) if err != nil { return err } return nil }) tests.Assert(t, err == nil) tests.Assert(t, utils.SortedStringHas(cluster.Info.Nodes, node.Id)) // Node delete the drives err = app.db.Update(func(tx *bolt.Tx) error { entry, err = NewNodeEntryFromId(tx, node.Id) if err != nil { return err } entry.DeviceDelete("123") entry.DeviceDelete("456") return entry.Save(tx) }) tests.Assert(t, err == nil) // Now delete node req, err = http.NewRequest("DELETE", ts.URL+"/nodes/"+node.Id, nil) tests.Assert(t, err == nil) r, err = http.DefaultClient.Do(req) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err = r.Location() tests.Assert(t, err == nil) // Wait for deletion for { r, err := http.Get(location.String()) tests.Assert(t, err == nil) if r.Header.Get("X-Pending") == "true" { tests.Assert(t, r.StatusCode == http.StatusOK) time.Sleep(time.Millisecond * 10) continue } else { tests.Assert(t, r.StatusCode == http.StatusNoContent) break } } // Check db to make sure key is removed err = app.db.View(func(tx *bolt.Tx) error { _, err = NewNodeEntryFromId(tx, node.Id) return err }) tests.Assert(t, err == ErrNotFound) // Check the cluster does not have this node id r, err = http.Get(ts.URL + "/clusters/" + clusterinfo.Id) tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") err = utils.GetJsonFromResponse(r, &clusterinfo) tests.Assert(t, len(clusterinfo.Nodes) == 0) // It should have deregistered the node // We should be able to add it again r, err = http.Post(ts.URL+"/nodes", "application/json", bytes.NewBuffer(request)) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusAccepted) location, err = r.Location() tests.Assert(t, err == nil) // Query queue until finished for { r, err = http.Get(location.String()) tests.Assert(t, err == nil) tests.Assert(t, r.StatusCode == http.StatusOK) if r.ContentLength <= 0 { time.Sleep(time.Millisecond * 10) continue } else { // Should have node information here tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") err = utils.GetJsonFromResponse(r, &node) tests.Assert(t, err == nil) break } } }
func TestClusterList(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Save some objects in the database numclusters := 5 err := app.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(BOLTDB_BUCKET_CLUSTER)) if b == nil { return errors.New("Unable to open bucket") } for i := 0; i < numclusters; i++ { var entry ClusterEntry entry.Info.Id = fmt.Sprintf("%v", 5000+i) buffer, err := entry.Marshal() if err != nil { return err } err = b.Put([]byte(entry.Info.Id), buffer) if err != nil { return err } } return nil }) tests.Assert(t, err == nil) // Now that we have some data in the database, we can // make a request for the clutser list r, err := http.Get(ts.URL + "/clusters") tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg api.ClusterListResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) // Thanks to BoltDB they come back in order mockid := 5000 // This is the mock id value we set above for _, id := range msg.Clusters { tests.Assert(t, id == fmt.Sprintf("%v", mockid)) mockid++ } }
func TestClusterInfo(t *testing.T) { tmpfile := tests.Tempfile() defer os.Remove(tmpfile) // Create the app app := NewTestApp(tmpfile) defer app.Close() router := mux.NewRouter() app.SetRoutes(router) // Setup the server ts := httptest.NewServer(router) defer ts.Close() // Create a new ClusterInfo entry := NewClusterEntry() entry.Info.Id = "123" for _, node := range []string{"a1", "a2", "a3"} { entry.NodeAdd(node) } for _, vol := range []string{"b1", "b2", "b3"} { entry.VolumeAdd(vol) } // Save the info in the database err := app.db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(BOLTDB_BUCKET_CLUSTER)) if b == nil { return errors.New("Unable to open bucket") } buffer, err := entry.Marshal() if err != nil { return err } err = b.Put([]byte(entry.Info.Id), buffer) if err != nil { return err } return nil }) tests.Assert(t, err == nil) // Now that we have some data in the database, we can // make a request for the clutser list r, err := http.Get(ts.URL + "/clusters/" + "123") tests.Assert(t, r.StatusCode == http.StatusOK) tests.Assert(t, err == nil) tests.Assert(t, r.Header.Get("Content-Type") == "application/json; charset=UTF-8") // Read response var msg api.ClusterInfoResponse err = utils.GetJsonFromResponse(r, &msg) tests.Assert(t, err == nil) // Check values are equal tests.Assert(t, entry.Info.Id == msg.Id) tests.Assert(t, entry.Info.Volumes[0] == msg.Volumes[0]) tests.Assert(t, entry.Info.Volumes[1] == msg.Volumes[1]) tests.Assert(t, entry.Info.Volumes[2] == msg.Volumes[2]) tests.Assert(t, entry.Info.Nodes[0] == msg.Nodes[0]) tests.Assert(t, entry.Info.Nodes[1] == msg.Nodes[1]) tests.Assert(t, entry.Info.Nodes[2] == msg.Nodes[2]) }