예제 #1
0
파일: storage.go 프로젝트: skyrings/bigfin
func (s *CephProvider) UpdateStorage(req models.RpcRequest, resp *models.RpcResponse) error {
	ctxt := req.RpcRequestContext
	cluster_id_str := req.RpcRequestVars["cluster-id"]
	cluster_id, err := uuid.Parse(cluster_id_str)
	if err != nil {
		logger.Get().Error(
			"%s - Error parsing the cluster id: %s. error: %v",
			ctxt,
			cluster_id_str,
			err)
		*resp = utils.WriteResponse(
			http.StatusBadRequest,
			fmt.Sprintf(
				"Error parsing the cluster id: %s",
				cluster_id_str))
		return err
	}
	storage_id_str := req.RpcRequestVars["storage-id"]
	storage_id, err := uuid.Parse(storage_id_str)
	if err != nil {
		logger.Get().Error(
			"%s - Error parsing the storage id: %s. error: %v",
			ctxt,
			storage_id_str,
			err)
		*resp = utils.WriteResponse(
			http.StatusBadRequest,
			fmt.Sprintf(
				"Error parsing the storage id: %s",
				storage_id_str))
		return err
	}
	var request models.AddStorageRequest
	if err := json.Unmarshal(req.RpcRequestData, &request); err != nil {
		logger.Get().Error(
			"%s - Unbale to parse the request. error: %v",
			ctxt,
			err)
		*resp = utils.WriteResponse(
			http.StatusBadRequest,
			fmt.Sprintf(
				"Unbale to parse the request. error: %v",
				err))
		return err
	}

	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE)
	var storage models.Storage
	if err := coll.Find(bson.M{"storageid": *storage_id}).One(&storage); err != nil {
		logger.Get().Error(
			"%s - Error getting detals of storage: %v on cluster: %v. error: %v",
			ctxt,
			*storage_id,
			*cluster_id,
			err)
		*resp = utils.WriteResponse(
			http.StatusInternalServerError,
			fmt.Sprintf(
				"Error getting the details of storage: %v",
				*storage_id))
		return err
	}
	id, err := strconv.Atoi(storage.Options["id"])
	if err != nil {
		logger.Get().Error(
			"%s - Error getting id of the pool: %v of cluster: %v. error: %v",
			ctxt,
			*storage_id,
			*cluster_id,
			err)
		*resp = utils.WriteResponse(
			http.StatusInternalServerError,
			fmt.Sprintf(
				"Error getting id of the pool: %v",
				*storage_id))
		return err
	}
	asyncTask := func(t *task.Task) {
		sessionCopy := db.GetDatastore().Copy()
		defer sessionCopy.Close()
		coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE)
		for {
			select {
			case <-t.StopCh:
				return
			default:
				t.UpdateStatus("Started ceph provider pool updation: %v", t.ID)
				if request.Name != "" && (request.Replicas != 0 || len(request.Options) != 0) {
					utils.FailTask(
						fmt.Sprintf(
							"Invalid mix of fields to update for storage: %v of cluster: %v. "+
								"Name change cannot be mixed with other changes.",
							*storage_id,
							*cluster_id),
						fmt.Errorf("%s-Invalid mix of fields to update", ctxt),
						t)
					return
				}
				for key := range request.Options {
					if ok := skyring_util.StringInSlice(key, validConfigs); !ok {
						utils.FailTask(
							fmt.Sprintf(
								"Invalid configuration: %s mentioned for storage: %v of cluster: %v",
								key,
								*storage_id,
								*cluster_id),
							fmt.Errorf("%s-%v", ctxt, err),
							t)
						return
					}
				}
				t.UpdateStatus("Getting a radom mon from cluster")
				monnode, err := GetCalamariMonNode(*cluster_id, ctxt)
				if err != nil {
					utils.FailTask(
						fmt.Sprintf(
							"Error getting mon node from cluster: %v",
							*cluster_id),
						fmt.Errorf("%s-%v", ctxt, err),
						t)
					return
				}
				var updatedFields = make(map[string]interface{})
				if request.Name != "" {
					updatedFields["name"] = request.Name
				}
				if request.Replicas != 0 {
					updatedFields["size"] = request.Replicas
				}
				if request.QuotaEnabled {
					for key, value := range request.QuotaParams {
						reqVal, _ := strconv.ParseUint(value, 10, 64)
						updatedFields[key] = uint64(reqVal)
					}
				} else {
					if request.QuotaParams["quota_max_objects"] == "0" && request.QuotaParams["quota_max_bytes"] == "0" {
						updatedFields["quota_max_objects"] = 0
						updatedFields["quota_max_bytes"] = 0
					}
				}
				for key, value := range request.Options {
					reqVal, _ := strconv.ParseUint(value, 10, 32)
					updatedFields[key] = uint(reqVal)
				}
				t.UpdateStatus("Updating pool details")
				ok, err := cephapi_backend.UpdatePool(
					monnode.Hostname,
					*cluster_id, id,
					updatedFields,
					ctxt)
				if err != nil || !ok {
					utils.FailTask(
						fmt.Sprintf(
							"Error setting the configurations for storage: %v on cluster: %v",
							*storage_id,
							*cluster_id),
						fmt.Errorf("%s-%v", ctxt, err),
						t)
					return
				}
				var filter bson.M = make(map[string]interface{})
				var updates bson.M = make(map[string]interface{})
				filter["storageid"] = *storage_id
				filter["clusterid"] = *cluster_id
				if request.Name != "" {
					updates["name"] = request.Name
				}
				if request.Replicas != 0 {
					updates["replicas"] = request.Replicas
				}
				if request.QuotaEnabled {
					updates["quotaenabled"] = true
					params := make(map[string]string)
					for key, value := range request.QuotaParams {
						params[key] = string(value)
					}
					updates["quotaparams"] = params
				} else {
					if request.QuotaParams["quota_max_objects"] == "0" && request.QuotaParams["quota_max_bytes"] == "0" {
						updates["quotaenabled"] = false
						updates["quotaparams"] = map[string]string{}
					}
				}

				if value, ok := request.Options["pg_num"]; ok {
					updates["options.pgp_num"] = value
				}
				t.UpdateStatus("Persisting pool updates in DB")
				if err := coll.Update(filter, bson.M{"$set": updates}); err != nil {
					utils.FailTask(
						fmt.Sprintf(
							"Error updating storage entity: %v of cluster: %v",
							*storage_id,
							*cluster_id),
						fmt.Errorf("%s-%v", ctxt, err),
						t)
				}

				cluster, err := getCluster(*cluster_id)
				if err != nil {
					logger.Get().Error("%s - Failed to get details of cluster: %s. error: %v", ctxt, *cluster_id, err)
				} else {
					initMonitoringRoutines(ctxt, cluster, (*monnode).Hostname, []interface{}{FetchOSDStats})
					UpdatePgNumToSummaries(cluster, ctxt)
				}

				if _, ok := updates["name"]; ok {
					coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_BLOCK_DEVICES)
					if _, err := coll.UpdateAll(filter, bson.M{"$set": bson.M{"storagename": updates["name"]}}); err != nil && err != mgo.ErrNotFound {
						utils.FailTask(
							fmt.Sprintf(
								"Storage name has changed for storage:%v. Error while updating this info for RBDs in cluster:%v",
								*storage_id,
								*cluster_id),
							fmt.Errorf("%s-%v", ctxt, err),
							t)
					}
				}
				t.UpdateStatus("Success")
				t.Done(models.TASK_STATUS_SUCCESS)
				return
			}
		}
	}
	if taskId, err := bigfin_task.GetTaskManager().Run(
		bigfin_conf.ProviderName,
		"CEPH-UpdateStorage",
		asyncTask,
		nil,
		nil,
		nil); err != nil {
		logger.Get().Error(
			"%s-Task creation failed for update storage on cluster: %v. error: %v",
			ctxt,
			*cluster_id,
			err)
		*resp = utils.WriteResponse(
			http.StatusInternalServerError,
			"Task creation failed for storage update")
		return err
	} else {
		*resp = utils.WriteAsyncResponse(
			taskId,
			fmt.Sprintf(
				"Task Created for update storage on cluster: %v",
				*cluster_id),
			[]byte{})
	}
	return nil
}
예제 #2
0
func (s *CephProvider) GetClusterNodesForImport(req models.RpcRequest, resp *models.RpcResponse) error {
	ctxt := req.RpcRequestContext
	bootstrapNode := req.RpcRequestVars["bootstrapnode"]
	var clusterForImport models.ClusterForImport

	out, err := cephapi_backend.GetCluster(bootstrapNode, ctxt)
	if err != nil {
		logger.Get().Error(
			"%s-Error getting cluster details. error: %v",
			ctxt,
			err)
		*resp = utils.WriteResponse(
			http.StatusInternalServerError,
			"Error getting cluster details")
		return err
	}
	clusterForImport.ClusterName = out.Name
	clusterForImport.ClusterId = out.Id
	clusterForImport.Compatible = true

	nodes, err := cephapi_backend.GetClusterNodes(bootstrapNode, out.Id, ctxt)
	if err != nil {
		logger.Get().Error(
			"%s-Error getting nodes participating in the cluster: %v",
			ctxt,
			out.Id)
		*resp = utils.WriteResponse(
			http.StatusInternalServerError,
			"Error getting nodes participating in the cluster")
		return err
	}
	var clusterNodes []models.NodeForImport
	sessionCopy := db.GetDatastore().Copy()
	defer sessionCopy.Close()
	coll := sessionCopy.DB(conf.SystemConfig.DBConfig.Database).C(models.COLL_NAME_STORAGE_NODES)
	var fetchedNode models.Node
	for _, node := range nodes {
		clusterNode := models.NodeForImport{
			Name: node.FQDN,
		}
		var nodeType []string
		for _, service := range node.Services {
			switch service.Type {
			case bigfin_models.NODE_SERVICE_MON:
				if ok := skyring_util.StringInSlice(bigfin_models.NODE_SERVICE_MON, nodeType); !ok {
					nodeType = append(nodeType, bigfin_models.NODE_SERVICE_MON)
				}
			case bigfin_models.NODE_SERVICE_OSD:
				if ok := skyring_util.StringInSlice(bigfin_models.NODE_SERVICE_OSD, nodeType); !ok {
					nodeType = append(nodeType, bigfin_models.NODE_SERVICE_OSD)
				}
			}
		}
		clusterNode.Type = nodeType
		if strings.HasPrefix(bootstrapNode, node.FQDN) {
			if node.CephVersion != "" && node.CephVersion != "null" {
				nodeVerStr := fmt.Sprintf(
					"%s.%s",
					strings.Split(node.CephVersion, ".")[0],
					strings.Split(node.CephVersion, ".")[1])
				nodeCephVersion, _ := strconv.ParseFloat(nodeVerStr, 64)
				clusterForImport.Compatible = (nodeCephVersion >= bigfin_conf.ProviderConfig.Provider.CompatVersion)
				clusterForImport.Version = nodeVerStr
			}
		}
		if err := coll.Find(
			bson.M{"hostname": node.FQDN}).One(&fetchedNode); err != nil {
			clusterNode.Found = false
		} else {
			clusterNode.Found = true
			clusterNode.Name = fetchedNode.Hostname
		}
		clusterNodes = append(clusterNodes, clusterNode)
	}

	clusterForImport.Nodes = clusterNodes
	result, err := json.Marshal(clusterForImport)
	if err != nil {
		logger.Get().Error(
			"%s-Error forming the output for import cluster nodes. error: %v",
			ctxt,
			err)
		*resp = utils.WriteResponse(
			http.StatusInternalServerError,
			fmt.Sprintf(
				"Error forming the output. error: %v",
				err))
		return err
	}
	*resp = utils.WriteResponseWithData(http.StatusOK, "", result)
	return nil
}