diff --git a/CHANGELOG.md b/CHANGELOG.md index f66e05ce..d625d8af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Crash when calling NodePublishVolume on non-existent volume ([#96]) +- Fix an issue where newly created volumes would not be placed on any nodes, leaving them unusable ([#99]) [#96]: https://github.com/piraeusdatastore/linstor-csi/issues/96 +[#99]: https://github.com/piraeusdatastore/linstor-csi/issues/99 ## [0.10.1] - 2020-11-19 diff --git a/pkg/client/linstor.go b/pkg/client/linstor.go index ded58b0d..1f21934d 100644 --- a/pkg/client/linstor.go +++ b/pkg/client/linstor.go @@ -300,17 +300,22 @@ func (s *Linstor) Create(ctx context.Context, vol *volume.Info, req *csi.CreateV return err } + logger.Debug("reconcile volume placement") + err = s.reconcileResourcePlacement(ctx, vol, ¶ms, rDef.Name, req) + if err != nil { + logger.Debugf("reconcile volume placement failed: %v", err) + return err + } + + // saveVolume() makes the volume eligible for further use, i.e. this method will not be called again once saveVolume + // was used. logger.Debug("update volume information with resource definition information") vol.ID = rDef.Name if err := s.saveVolume(ctx, vol); err != nil { return err } - volumeScheduler, err := s.schedulerByPlacementPolicy(vol) - if err != nil { - return err - } - return volumeScheduler.Create(ctx, vol, req) + return nil } // Delete removes a resource, all of its volumes, and snapshots from LINSTOR. @@ -774,6 +779,39 @@ func (s *Linstor) reconcileVolumeDefinition(ctx context.Context, info *volume.In return &vDef, nil } +func (s *Linstor) reconcileResourcePlacement(ctx context.Context, vol *volume.Info, volParams *volume.Parameters, rdName string, req *csi.CreateVolumeRequest) error { + logger := s.log.WithFields(logrus.Fields{ + "volume": vol.Name, + }) + logger.Info("reconcile resource placement for volume") + + + resources, err := s.client.Resources.GetAll(ctx, rdName) + if err != nil { + return err + } + + // Check that at least as many resources are placed as specified in the volume parameters + expectedAutoResources := int(volParams.PlacementCount) + expectedManualResources := len(volParams.ClientList) + len(volParams.NodeList) + if len(resources) >= expectedAutoResources && len(resources) >= expectedManualResources { + logger.Debug("resources already placed") + return nil + } + + volumeScheduler, err := s.schedulerByPlacementPolicy(vol) + if err != nil { + return err + } + + err = volumeScheduler.Create(ctx, vol, req) + if err != nil { + return err + } + + return nil +} + // store a representation of a volume into the aux props of a resource definition. func (s *Linstor) saveVolume(ctx context.Context, vol *volume.Info) error { serializedVol, err := json.Marshal(vol)