예제 #1
0
파일: nodes.go 프로젝트: kshlm/heketi
func (n *NodeServer) NodeAddHandler(w http.ResponseWriter, r *http.Request) {
	var msg requests.NodeAddRequest

	err := utils.GetJsonFromRequest(r, &msg)
	if err != nil {
		http.Error(w, "request unable to be parsed", 422)
		return
	}

	// Add node here
	info, err := n.plugin.NodeAdd(&msg)

	// :TODO:
	// Depending on the error returned here,
	// we should return the correct error code
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send back we created it (as long as we did not fail)
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(info); err != nil {
		panic(err)
	}
}
예제 #2
0
파일: volumes.go 프로젝트: kshlm/heketi
func (v *VolumeServer) VolumeCreateHandler(w http.ResponseWriter, r *http.Request) {
	var request requests.VolumeCreateRequest

	err := utils.GetJsonFromRequest(r, &request)
	if err != nil {
		http.Error(w, "request unable to be parsed", 422)
		return
	}

	// Create volume here
	result, err := v.plugin.VolumeCreate(&request)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Send back we created it (as long as we did not fail)
	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	w.WriteHeader(http.StatusCreated)
	if err := json.NewEncoder(w).Encode(result); err != nil {
		panic(err)
	}
}
예제 #3
0
파일: nodes.go 프로젝트: kshlm/heketi
func (n *NodeServer) NodeAddDeviceHandler(w http.ResponseWriter, r *http.Request) {

	// Get list
	var req requests.DeviceAddRequest

	err := utils.GetJsonFromRequest(r, &req)
	if err != nil {
		http.Error(w, "request unable to be parsed", 422)
		return
	}

	// Get the id from the URL
	vars := mux.Vars(r)

	// Get the id from the URL
	id := vars["id"]

	// Call plugin
	n.plugin.NodeAddDevice(id, &req)

	// Write msg
	w.WriteHeader(http.StatusCreated)
}
예제 #4
0
파일: app_node.go 프로젝트: Zandrr/heketi
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
	}

	// Create a node entry
	node := NewNodeEntryFromRequest(&msg)

	// 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
	}

	logger.Info("Adding node %v", node.Info.Hostnames.Manage[0])
	a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) {
		time.Sleep(1 * time.Second)
		logger.Info("Added node " + node.Info.Id)
		return "/nodes/" + node.Info.Id, nil
	})
}
예제 #5
0
파일: app_device.go 프로젝트: Zandrr/heketi
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 len(msg.Devices) <= 0 {
		http.Error(w, "no devices added", http.StatusBadRequest)
		return
	}

	// Check the node is in the db
	err = a.db.View(func(tx *bolt.Tx) error {
		_, 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 devices %+v to node %v", msg.Devices, msg.NodeId)

	// Add device in an asynchronous function
	a.asyncManager.AsyncHttpRedirectFunc(w, r, func() (string, error) {

		sg := utils.NewStatusGroup()
		for index := range msg.Devices {
			sg.Add(1)

			// Add each drive
			go func(dev *Device) {
				defer sg.Done()

				// Pretend work
				time.Sleep(1 * time.Second)

				device := NewDeviceEntryFromRequest(dev, msg.NodeId)
				err := a.db.Update(func(tx *bolt.Tx) error {
					node, err := NewNodeEntryFromId(tx, msg.NodeId)
					if err != nil {
						return err
					}

					// Add device to node
					node.DeviceAdd(device.Info.Id)

					// Commit
					err = node.Save(tx)
					if err != nil {
						return err
					}

					// Save drive
					err = device.Save(tx)
					if err != nil {
						return err
					}

					return nil

				})
				if err != nil {
					sg.Err(err)
				}

				logger.Info("Added device %v", dev.Name)

			}(&msg.Devices[index])
		}

		// Done
		// Returning a null string instructs the async manager
		// to return http status of 204 (No Content)
		return "", sg.Result()
	})

}
예제 #6
0
파일: app_device.go 프로젝트: pkoro/heketi
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
	})

}
예제 #7
0
파일: app_node.go 프로젝트: pkoro/heketi
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
	})
}
예제 #8
0
파일: app_volume.go 프로젝트: pkoro/heketi
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
	})

}
예제 #9
0
파일: app_volume.go 프로젝트: pkoro/heketi
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
	})

}