Esempio n. 1
0
// 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)
}
Esempio n. 2
0
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
	})
}
Esempio n. 3
0
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
	})

}
Esempio n. 4
0
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
	})

}
Esempio n. 5
0
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
	})

}