// Func Save OMIT func (a *App) SaveKey(w http.ResponseWriter, r *http.Request) { var msg AppSaveRequest vars := mux.Vars(r) key := vars["key"] // Unmarshal using github.com/heketi/utils err := utils.GetJsonFromRequest(r, &msg) if err != nil { http.Error(w, "request unable to be parsed", 422) return } // Check information in JSON request if len(key) == 0 || len(msg.Value) == 0 { http.Error(w, "Missing infomration", http.StatusBadRequest) return } a.lock.Lock() a.keys[key] = msg.Value a.lock.Unlock() w.WriteHeader(http.StatusCreated) }
func (a *App) NodeAdd(w http.ResponseWriter, r *http.Request) { var msg NodeAddRequest err := utils.GetJsonFromRequest(r, &msg) if err != nil { http.Error(w, "request unable to be parsed", 422) return } // Check information in JSON request if len(msg.Hostnames.Manage) == 0 { http.Error(w, "Manage hostname missing", http.StatusBadRequest) return } if len(msg.Hostnames.Storage) == 0 { http.Error(w, "Storage hostname missing", http.StatusBadRequest) return } // Check for correct values for _, name := range append(msg.Hostnames.Manage, msg.Hostnames.Storage...) { if name == "" { http.Error(w, "Hostname cannot be an empty string", http.StatusBadRequest) return } } // Get cluster and peer node var cluster *ClusterEntry var peer_node *NodeEntry err = a.db.View(func(tx *bolt.Tx) error { var err error cluster, err = NewClusterEntryFromId(tx, msg.ClusterId) if err == ErrNotFound { http.Error(w, "Cluster id does not exist", http.StatusNotFound) return err } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } // Get a node in the cluster to execute the Gluster peer command // only if there is more than one node if len(cluster.Info.Nodes) > 0 { peer_node, err = cluster.NodeEntryFromClusterIndex(tx, 0) if err != nil { logger.Err(err) return err } } return nil }) if err != nil { return } // Create a node entry node := NewNodeEntryFromRequest(&msg) // Add node logger.Info("Adding node %v", node.ManageHostName()) a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) { // Peer probe if there is at least one other node // TODO: What happens if the peer_node is not responding.. we need to choose another. if peer_node != nil { err := a.executor.PeerProbe(peer_node.ManageHostName(), node.ManageHostName()) if err != nil { return "", err } } // Add node entry into the db err = a.db.Update(func(tx *bolt.Tx) error { cluster, err := NewClusterEntryFromId(tx, msg.ClusterId) if err == ErrNotFound { http.Error(w, "Cluster id does not exist", http.StatusNotFound) return err } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } // Add node to cluster cluster.NodeAdd(node.Info.Id) // Save cluster err = cluster.Save(tx) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } // Save node err = node.Save(tx) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } return nil }) if err != nil { return "", err } logger.Info("Added node " + node.Info.Id) return "/nodes/" + node.Info.Id, nil }) }
func (a *App) VolumeCreate(w http.ResponseWriter, r *http.Request) { var msg VolumeCreateRequest err := utils.GetJsonFromRequest(r, &msg) if err != nil { http.Error(w, "request unable to be parsed", 422) return } // Check durability type switch msg.Durability.Type { case DURABILITY_STRING_EC: case DURABILITY_STRING_REPLICATE: case DURABILITY_STRING_DISTRIBUTE_ONLY: case "": msg.Durability.Type = DURABILITY_STRING_DISTRIBUTE_ONLY default: http.Error(w, "Unknown durability type", http.StatusBadRequest) return } // Check the message has devices if msg.Size < 1 { http.Error(w, "Invalid volume size", http.StatusBadRequest) return } if msg.Snapshot.Enable { if msg.Snapshot.Factor < 1 || msg.Snapshot.Factor > VOLUME_CREATE_MAX_SNAPSHOT_FACTOR { http.Error(w, "Invalid snapshot factor", http.StatusBadRequest) return } } // Check replica values if msg.Durability.Type == DURABILITY_STRING_REPLICATE { if msg.Durability.Replicate.Replica > 3 { http.Error(w, "Invalid replica value", http.StatusBadRequest) return } } // Check Disperse combinations if msg.Durability.Type == DURABILITY_STRING_EC { d := msg.Durability.Disperse // Place here correct combinations switch { case d.Data == 4 && d.Redundancy == 2: case d.Data == 8 && d.Redundancy == 3: case d.Data == 8 && d.Redundancy == 4: default: http.Error(w, fmt.Sprintf("Invalid dispersion combination: %v+%v", d.Data, d.Redundancy), http.StatusBadRequest) return } } // Check that the clusters requested are avilable err = a.db.View(func(tx *bolt.Tx) error { // Check we have clusters // :TODO: All we need to do is check for one instead of gathering all keys clusters, err := ClusterList(tx) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } if len(clusters) == 0 { http.Error(w, fmt.Sprintf("No clusters configured"), http.StatusBadRequest) return ErrNotFound } // Check the clusters requested are correct for _, clusterid := range msg.Clusters { _, err := NewClusterEntryFromId(tx, clusterid) if err != nil { http.Error(w, fmt.Sprintf("Cluster id %v not found", clusterid), http.StatusBadRequest) return err } } return nil }) if err != nil { return } // Create a volume entry vol := NewVolumeEntryFromRequest(&msg) // Add device in an asynchronous function a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) { logger.Info("Creating volume %v", vol.Info.Id) err := vol.Create(a.db, a.executor, a.allocator) if err != nil { logger.LogError("Failed to create volume: %v", err) return "", err } logger.Info("Created volume %v", vol.Info.Id) // Done return "/volumes/" + vol.Info.Id, nil }) }
func (a *App) DeviceAdd(w http.ResponseWriter, r *http.Request) { var msg DeviceAddRequest err := utils.GetJsonFromRequest(r, &msg) if err != nil { http.Error(w, "request unable to be parsed", 422) return } // Check the message has devices if msg.Name == "" { http.Error(w, "no devices added", http.StatusBadRequest) return } // Check the node is in the db var node *NodeEntry err = a.db.View(func(tx *bolt.Tx) error { var err error node, err = NewNodeEntryFromId(tx, msg.NodeId) if err == ErrNotFound { http.Error(w, "Node id does not exist", http.StatusNotFound) return err } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } return nil }) if err != nil { return } // Log the devices are being added logger.Info("Adding device %v to node %v", msg.Name, msg.NodeId) // Add device in an asynchronous function a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (seeOtherUrl string, e error) { // Create device entry device := NewDeviceEntryFromRequest(&msg) // Setup device on node info, err := a.executor.DeviceSetup(node.ManageHostName(), device.Info.Name, device.Info.Id) if err != nil { return "", err } // Create an entry for the device and set the size device.StorageSet(info.Size) device.SetExtentSize(info.ExtentSize) // Setup garbage collector on error defer func() { if e != nil { a.executor.DeviceTeardown(node.ManageHostName(), device.Info.Name, device.Info.Id) } }() // Save on db err = a.db.Update(func(tx *bolt.Tx) error { nodeEntry, err := NewNodeEntryFromId(tx, msg.NodeId) if err != nil { return err } // Add device to node nodeEntry.DeviceAdd(device.Info.Id) clusterEntry, err := NewClusterEntryFromId(tx, nodeEntry.Info.ClusterId) if err != nil { return err } // Commit err = nodeEntry.Save(tx) if err != nil { return err } // Save drive err = device.Save(tx) if err != nil { return err } // Add to allocator err = a.allocator.AddDevice(clusterEntry, nodeEntry, device) if err != nil { return err } return nil }) if err != nil { return "", err } logger.Info("Added device %v", msg.Name) // Done // Returning a null string instructs the async manager // to return http status of 204 (No Content) return "", nil }) }
func (a *App) VolumeExpand(w http.ResponseWriter, r *http.Request) { logger.Debug("In VolumeExpand") // Get the id from the URL vars := mux.Vars(r) id := vars["id"] var msg VolumeExpandRequest err := utils.GetJsonFromRequest(r, &msg) if err != nil { http.Error(w, "request unable to be parsed", 422) return } logger.Debug("Msg: %v", msg) // Check the message if msg.Size < 1 { http.Error(w, "Invalid volume size", http.StatusBadRequest) return } logger.Debug("Size: %v", msg.Size) // Get volume entry var volume *VolumeEntry err = a.db.View(func(tx *bolt.Tx) error { // Access volume entry var err error volume, err = NewVolumeEntryFromId(tx, id) if err == ErrNotFound { http.Error(w, err.Error(), http.StatusNotFound) return err } else if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return err } return nil }) if err != nil { return } // Expand device in an asynchronous function a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) { logger.Info("Expanding volume %v", volume.Info.Id) err := volume.Expand(a.db, a.executor, a.allocator, msg.Size) if err != nil { logger.LogError("Failed to expand volume %v", volume.Info.Id) return "", err } logger.Info("Expanded volume %v", volume.Info.Id) // Done return "/volumes/" + volume.Info.Id, nil }) }