public override async Task <ControllerPublishVolumeResponse> ControllerPublishVolume(
            ControllerPublishVolumeRequest request,
            ServerCallContext context)
        {
            var response = new ControllerPublishVolumeResponse();

            var id = request.VolumeId;

            using (logger.BeginKeyValueScope("volume_id", id))
                using (var _s = logger.StepInformation("{0}", nameof(ControllerPublishVolume)))
                {
                    try
                    {
                        var ctx = new Helpers.Azure.DataProviderContext <ManagedDiskConfig>();
                        await contextConfig.Provide(ctx);

                        var actx = new AzureAuthConfigProviderContext {
                            Secrets = request.ControllerPublishSecrets
                        };

                        var setupService = setupServiceFactory.Create(provider.Provide(actx), ctx.Result.SubscriptionId);
                        var vmRid        = ResourceId.FromString(request.NodeId);
                        var diskId       = ResourceId.FromString(id);

                        var info = await setupService.AddAsync(vmRid, diskId);

                        response.PublishInfo.Add("lun", info.Lun.ToString());
                    }
                    catch (Exception ex)
                    {
                        logger.LogError(ex, "Exception in ControllerPublishVolume");
                        throw new RpcException(new Status(StatusCode.Internal, ex.Message));
                    }

                    _s.Commit();
                }
            return(response);
        }
        public override async Task <ControllerPublishVolumeResponse> ControllerPublishVolume(ControllerPublishVolumeRequest request, ServerCallContext context)
        {
            var shared = false;

            if (request.Readonly)
            {
                throw new RpcException(new Status(StatusCode.InvalidArgument, string.Empty), "readonly attach no supported");
            }

            switch (request.VolumeCapability.AccessMode.Mode)
            {
            case VolumneAccessMode.SingleNodeWriter:
                shared = false;
                break;

            default:
                throw new RpcException(new Status(StatusCode.InvalidArgument, string.Empty),
                                       "not supported volume access mode");
            }

            switch (request.VolumeCapability.AccessTypeCase)
            {
            case VolumeCapability.AccessTypeOneofCase.Mount:
                //throw new RpcException(new Status(StatusCode.InvalidArgument, string.Empty),
                //    "not supported volume access type");
                //maybe SMB3 FileServer support
                //entry.Mount.MountFlags;
                //entry.Mount.FsType;
                break;

            case VolumeCapability.AccessTypeOneofCase.Block:
                break;

            //case VolumeCapability.AccessTypeOneofCase.None:
            default:
                throw new RpcException(new Status(StatusCode.InvalidArgument, string.Empty),
                                       "unknown volume access type");
            }

            //request.VolumeId
            //request.VolumeContext

            var foundVolume = await _service.GetVolumesAsync(new HypervVolumeFilter
            {
                Name    = request.VolumeId,
                Storage = request.VolumeContext["Storage"]
            })
                              .FirstOrDefaultAsync(context.CancellationToken);

            if (foundVolume is null)
            {
                throw new RpcException(new Status(StatusCode.NotFound, string.Empty),
                                       "volume not found");
            }

            var vmId = Guid.Parse(request.NodeId);

            //var volumePath = request.VolumeContext["Path"];

            HypervVirtualMachineVolumeInfo vmVolume;

            var flow = await _service.GetVolumeFlowsAsnyc(new HypervVolumeFlowFilter
            {
                VolumePath = foundVolume.Path
            })
                       .FirstOrDefaultAsync(context.CancellationToken);

            if (flow != null)
            {
                if (!shared && flow.VMId != vmId)
                {
                    throw new RpcException(new Status(StatusCode.FailedPrecondition, string.Empty),
                                           $"volume published on node[{flow.VMId}]");
                }

                //todo check shared volume_capability

                vmVolume = await _service.GetVirtualMachineVolumesAsync(flow.VMId, new HypervVirtualMachineVolumeFilter
                {
                    VolumePath = flow.Path,
                    Host       = flow.Host
                })
                           .FirstAsync(context.CancellationToken);
            }
            else
            {
                var volume = await _service.GetVolumeAsync(foundVolume.Path, null, context.CancellationToken);

                if (shared != volume.Shared)
                {
                    throw new RpcException(new Status(StatusCode.InvalidArgument, string.Empty),
                                           "volume sharing ambiguous");
                }

                //maybe check volume.Attached=false

                var vm = await _service.GetVirtualMachinesAsync(new HypervVirtualMachineFilter
                {
                    Id = vmId
                })
                         .FirstOrDefaultAsync(context.CancellationToken);

                if (vm is null)
                {
                    throw new RpcException(new Status(StatusCode.NotFound, string.Empty),
                                           "node not found");
                }

                vmVolume = await _service.AttachVolumeAsync(new HypervAttachVolumeRequest
                {
                    VMId       = vm.Id,
                    VolumePath = volume.Path,
                    Host       = vm.Host
                },
                                                            context.CancellationToken);
            }

            //todo error:
            //Volume published but is incompatible, 6 ALREADY_EXISTS
            //Max volumes attached, 8 RESOURCE_EXHAUSTED

            var rsp = new ControllerPublishVolumeResponse
            {
            };

            rsp.PublishContext.Add("ControllerNumber", vmVolume.ControllerNumber.ToString());
            rsp.PublishContext.Add("ControllerLocation", vmVolume.ControllerLocation.ToString());

            return(rsp);
        }