public override async Task <ListVolumesResponse> ListVolumes(ListVolumesRequest request, ServerCallContext context)
        {
            //todo request.MaxEntries,
            //request.StartingToken

            var volumeSource = _service.GetVolumesAsync(null);

            if (!string.IsNullOrEmpty(request.StartingToken))
            {
                if (!int.TryParse(request.StartingToken, out var startIndex))
                {
                    throw new RpcException(new Status(StatusCode.Aborted, string.Empty),
                                           "invalid starting_token");
                }

                volumeSource = volumeSource.Skip(startIndex);
            }

            if (request.MaxEntries > 0)
            {
                volumeSource = volumeSource.Take(request.MaxEntries);
            }

            var foundVolumes = await volumeSource
                               .ToListAsync(context.CancellationToken);

            var flows = await _service.GetVolumeFlowsAsnyc(null)
                        .ToListAsync(context.CancellationToken);

            var nextIndex = request.MaxEntries + foundVolumes.Count;

            var rsp = new ListVolumesResponse
            {
                NextToken = request.MaxEntries > 0 ? nextIndex.ToString() : string.Empty
            };

            foreach (var foundVolume in foundVolumes)
            {
                var volumeFlows = flows.Where(n => StringComparer.OrdinalIgnoreCase.Equals(foundVolume.Path, n.Path)).ToList();

                var hostNames = volumeFlows.Select(n => n.Host)
                                .Distinct(StringComparer.OrdinalIgnoreCase)
                                .DefaultIfEmpty(null);

                var errors           = new List <Exception>();
                HypervVolumeDetail v = null;

                foreach (var hostName in hostNames)
                {
                    //maybe stale record after remount to other node

                    try
                    {
                        v = await _service.GetVolumeAsync(foundVolume.Path, hostName, context.CancellationToken);

                        continue;
                    }
                    catch (Exception ex)
                    {
                        errors.Add(new Exception($"Getting volume details of '{foundVolume.Name}' at host '{hostName ?? "default"}' failed.", ex));
                    }
                }

                if (v is null)
                {
                    throw errors.Count switch
                          {
                              1 => errors[0],
                              _ => new AggregateException($"Getting volume details of '{foundVolume.Name}' failed.", errors),
                          };
                }

                var entry = new ListVolumesResponse.Types.Entry
                {
                    Volume = new Volume
                    {
                        VolumeId      = foundVolume.Name,
                        CapacityBytes = (long)v.SizeBytes,
                        //AccessibleTopology
                        //ContentSource
                    },
                    Status = new ListVolumesResponse.Types.VolumeStatus
                    {
                    }
                };
                entry.Volume.VolumeContext.Add("Id", v.Id.ToString());
                entry.Volume.VolumeContext.Add("Storage", v.Storage);
                entry.Volume.VolumeContext.Add("Path", v.Path);

                entry.Status.PublishedNodeIds.Add(volumeFlows.Select(n => n.VMId.ToString()));

                rsp.Entries.Add(entry);
            }

            return(rsp);
        }
Esempio n. 2
0
        public override async Task <ListVolumesResponse> ListVolumes(ListVolumesRequest request, ServerCallContext context)
        {
            _logger.LogDebug("list volumes from index {StartIndex}", request.StartingToken);

            //todo cache query
            var volumes = await _service.GetVolumesAsync(null).ToListAsync(context.CancellationToken);

            var startIndex = 0;

            if (!string.IsNullOrEmpty(request.StartingToken))
            {
                if (!int.TryParse(request.StartingToken, out startIndex))
                {
                    throw new RpcException(new Status(StatusCode.InvalidArgument, "invalid starting_token"));
                }
            }

            var rsp = new ListVolumesResponse
            {
            };

            if (request.MaxEntries > 0 && (volumes.Count - startIndex) > request.MaxEntries)
            {
                rsp.NextToken = (startIndex + request.MaxEntries).ToString();
            }

            var volumeSource = volumes.AsEnumerable();

            if (startIndex > 0)
            {
                volumeSource = volumeSource.Skip(startIndex);
            }

            if (request.MaxEntries > 0)
            {
                volumeSource = volumeSource.Take(request.MaxEntries);
            }

            await foreach (var r in _service.GetVolumeDetailsAsync(volumeSource, context.CancellationToken))
            {
                var entry = new ListVolumesResponse.Types.Entry
                {
                    Volume = new Volume
                    {
                        VolumeId = r.Info.Name
                                   //AccessibleTopology
                                   //ContentSource
                    },
                    Status = new ListVolumesResponse.Types.VolumeStatus
                    {
                    }
                };

                if (r.Detail is not null)
                {
                    var d = r.Detail;
                    entry.Volume.CapacityBytes = (long)(d.SizeBytes);
                    entry.Volume.VolumeContext.Add("Id", d.Id.ToString());
                    entry.Volume.VolumeContext.Add("Storage", d.Storage);
                    entry.Volume.VolumeContext.Add("Path", d.Path);
                    entry.Status.VolumeCondition = new VolumeCondition
                    {
                        Abnormal = false,
                        Message  = d.Attached ? "attached" : "detached"
                    };
                }

                if (r.Nodes.Length > 0)
                {
                    entry.Status.PublishedNodeIds.Add(r.Nodes);
                }

                if (r.Error is not null)
                {
                    entry.Status.VolumeCondition = new VolumeCondition
                    {
                        Abnormal = true,
                        Message  = r.Error.Message
                    };
                }

                rsp.Entries.Add(entry);
            }

            return(rsp);
        }