fake_client.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package fake
  14. import (
  15. "context"
  16. "errors"
  17. "strings"
  18. csipb "github.com/container-storage-interface/spec/lib/go/csi"
  19. "google.golang.org/grpc"
  20. "google.golang.org/grpc/codes"
  21. "google.golang.org/grpc/status"
  22. )
  23. const (
  24. // NodePublishTimeout_VolumeID is volume id that will result in NodePublish operation to timeout
  25. NodePublishTimeOut_VolumeID = "node-publish-timeout"
  26. // NodeStageTimeOut_VolumeID is a volume id that will result in NodeStage operation to timeout
  27. NodeStageTimeOut_VolumeID = "node-stage-timeout"
  28. )
  29. // IdentityClient is a CSI identity client used for testing
  30. type IdentityClient struct {
  31. nextErr error
  32. }
  33. // NewIdentityClient returns a new IdentityClient
  34. func NewIdentityClient() *IdentityClient {
  35. return &IdentityClient{}
  36. }
  37. // SetNextError injects expected error
  38. func (f *IdentityClient) SetNextError(err error) {
  39. f.nextErr = err
  40. }
  41. // GetPluginInfo returns plugin info
  42. func (f *IdentityClient) GetPluginInfo(ctx context.Context, in *csipb.GetPluginInfoRequest, opts ...grpc.CallOption) (*csipb.GetPluginInfoResponse, error) {
  43. return nil, nil
  44. }
  45. // GetPluginCapabilities implements csi method
  46. func (f *IdentityClient) GetPluginCapabilities(ctx context.Context, in *csipb.GetPluginCapabilitiesRequest, opts ...grpc.CallOption) (*csipb.GetPluginCapabilitiesResponse, error) {
  47. return nil, nil
  48. }
  49. // Probe implements csi method
  50. func (f *IdentityClient) Probe(ctx context.Context, in *csipb.ProbeRequest, opts ...grpc.CallOption) (*csipb.ProbeResponse, error) {
  51. return nil, nil
  52. }
  53. type CSIVolume struct {
  54. VolumeHandle string
  55. VolumeContext map[string]string
  56. Path string
  57. DeviceMountPath string
  58. FSType string
  59. MountFlags []string
  60. }
  61. // NodeClient returns CSI node client
  62. type NodeClient struct {
  63. nodePublishedVolumes map[string]CSIVolume
  64. nodeStagedVolumes map[string]CSIVolume
  65. stageUnstageSet bool
  66. expansionSet bool
  67. volumeStatsSet bool
  68. nodeGetInfoResp *csipb.NodeGetInfoResponse
  69. nodeVolumeStatsResp *csipb.NodeGetVolumeStatsResponse
  70. nextErr error
  71. }
  72. // NewNodeClient returns fake node client
  73. func NewNodeClient(stageUnstageSet bool) *NodeClient {
  74. return &NodeClient{
  75. nodePublishedVolumes: make(map[string]CSIVolume),
  76. nodeStagedVolumes: make(map[string]CSIVolume),
  77. stageUnstageSet: stageUnstageSet,
  78. volumeStatsSet: true,
  79. }
  80. }
  81. func NewNodeClientWithExpansion(stageUnstageSet bool, expansionSet bool) *NodeClient {
  82. return &NodeClient{
  83. nodePublishedVolumes: make(map[string]CSIVolume),
  84. nodeStagedVolumes: make(map[string]CSIVolume),
  85. stageUnstageSet: stageUnstageSet,
  86. expansionSet: expansionSet,
  87. }
  88. }
  89. func NewNodeClientWithVolumeStats(volumeStatsSet bool) *NodeClient {
  90. return &NodeClient{
  91. volumeStatsSet: volumeStatsSet,
  92. }
  93. }
  94. // SetNextError injects next expected error
  95. func (f *NodeClient) SetNextError(err error) {
  96. f.nextErr = err
  97. }
  98. func (f *NodeClient) SetNodeGetInfoResp(resp *csipb.NodeGetInfoResponse) {
  99. f.nodeGetInfoResp = resp
  100. }
  101. func (f *NodeClient) SetNodeVolumeStatsResp(resp *csipb.NodeGetVolumeStatsResponse) {
  102. f.nodeVolumeStatsResp = resp
  103. }
  104. // GetNodePublishedVolumes returns node published volumes
  105. func (f *NodeClient) GetNodePublishedVolumes() map[string]CSIVolume {
  106. return f.nodePublishedVolumes
  107. }
  108. // AddNodePublishedVolume adds specified volume to nodePublishedVolumes
  109. func (f *NodeClient) AddNodePublishedVolume(volID, deviceMountPath string, volumeContext map[string]string) {
  110. f.nodePublishedVolumes[volID] = CSIVolume{
  111. Path: deviceMountPath,
  112. VolumeContext: volumeContext,
  113. }
  114. }
  115. // GetNodeStagedVolumes returns node staged volumes
  116. func (f *NodeClient) GetNodeStagedVolumes() map[string]CSIVolume {
  117. return f.nodeStagedVolumes
  118. }
  119. // AddNodeStagedVolume adds specified volume to nodeStagedVolumes
  120. func (f *NodeClient) AddNodeStagedVolume(volID, deviceMountPath string, volumeContext map[string]string) {
  121. f.nodeStagedVolumes[volID] = CSIVolume{
  122. Path: deviceMountPath,
  123. VolumeContext: volumeContext,
  124. }
  125. }
  126. // NodePublishVolume implements CSI NodePublishVolume
  127. func (f *NodeClient) NodePublishVolume(ctx context.Context, req *csipb.NodePublishVolumeRequest, opts ...grpc.CallOption) (*csipb.NodePublishVolumeResponse, error) {
  128. if f.nextErr != nil {
  129. return nil, f.nextErr
  130. }
  131. if req.GetVolumeId() == "" {
  132. return nil, errors.New("missing volume id")
  133. }
  134. if req.GetTargetPath() == "" {
  135. return nil, errors.New("missing target path")
  136. }
  137. fsTypes := "block|ext4|xfs|zfs"
  138. fsType := req.GetVolumeCapability().GetMount().GetFsType()
  139. if !strings.Contains(fsTypes, fsType) {
  140. return nil, errors.New("invalid fstype")
  141. }
  142. if req.GetVolumeId() == NodePublishTimeOut_VolumeID {
  143. timeoutErr := status.Errorf(codes.DeadlineExceeded, "timeout exceeded")
  144. return nil, timeoutErr
  145. }
  146. f.nodePublishedVolumes[req.GetVolumeId()] = CSIVolume{
  147. VolumeHandle: req.GetVolumeId(),
  148. Path: req.GetTargetPath(),
  149. DeviceMountPath: req.GetStagingTargetPath(),
  150. VolumeContext: req.GetVolumeContext(),
  151. FSType: req.GetVolumeCapability().GetMount().GetFsType(),
  152. MountFlags: req.GetVolumeCapability().GetMount().MountFlags,
  153. }
  154. return &csipb.NodePublishVolumeResponse{}, nil
  155. }
  156. // NodeUnpublishVolume implements csi method
  157. func (f *NodeClient) NodeUnpublishVolume(ctx context.Context, req *csipb.NodeUnpublishVolumeRequest, opts ...grpc.CallOption) (*csipb.NodeUnpublishVolumeResponse, error) {
  158. if f.nextErr != nil {
  159. return nil, f.nextErr
  160. }
  161. if req.GetVolumeId() == "" {
  162. return nil, errors.New("missing volume id")
  163. }
  164. if req.GetTargetPath() == "" {
  165. return nil, errors.New("missing target path")
  166. }
  167. delete(f.nodePublishedVolumes, req.GetVolumeId())
  168. return &csipb.NodeUnpublishVolumeResponse{}, nil
  169. }
  170. // NodeStagevolume implements csi method
  171. func (f *NodeClient) NodeStageVolume(ctx context.Context, req *csipb.NodeStageVolumeRequest, opts ...grpc.CallOption) (*csipb.NodeStageVolumeResponse, error) {
  172. if f.nextErr != nil {
  173. return nil, f.nextErr
  174. }
  175. if req.GetVolumeId() == "" {
  176. return nil, errors.New("missing volume id")
  177. }
  178. if req.GetStagingTargetPath() == "" {
  179. return nil, errors.New("missing staging target path")
  180. }
  181. csiVol := CSIVolume{
  182. Path: req.GetStagingTargetPath(),
  183. VolumeContext: req.GetVolumeContext(),
  184. }
  185. fsType := ""
  186. fsTypes := "block|ext4|xfs|zfs"
  187. mounted := req.GetVolumeCapability().GetMount()
  188. if mounted != nil {
  189. fsType = mounted.GetFsType()
  190. csiVol.MountFlags = mounted.GetMountFlags()
  191. }
  192. if !strings.Contains(fsTypes, fsType) {
  193. return nil, errors.New("invalid fstype")
  194. }
  195. if req.GetVolumeId() == NodeStageTimeOut_VolumeID {
  196. timeoutErr := status.Errorf(codes.DeadlineExceeded, "timeout exceeded")
  197. return nil, timeoutErr
  198. }
  199. f.nodeStagedVolumes[req.GetVolumeId()] = csiVol
  200. return &csipb.NodeStageVolumeResponse{}, nil
  201. }
  202. // NodeUnstageVolume implements csi method
  203. func (f *NodeClient) NodeUnstageVolume(ctx context.Context, req *csipb.NodeUnstageVolumeRequest, opts ...grpc.CallOption) (*csipb.NodeUnstageVolumeResponse, error) {
  204. if f.nextErr != nil {
  205. return nil, f.nextErr
  206. }
  207. if req.GetVolumeId() == "" {
  208. return nil, errors.New("missing volume id")
  209. }
  210. if req.GetStagingTargetPath() == "" {
  211. return nil, errors.New("missing staging target path")
  212. }
  213. delete(f.nodeStagedVolumes, req.GetVolumeId())
  214. return &csipb.NodeUnstageVolumeResponse{}, nil
  215. }
  216. // NodeExpandVolume implements csi method
  217. func (f *NodeClient) NodeExpandVolume(ctx context.Context, req *csipb.NodeExpandVolumeRequest, opts ...grpc.CallOption) (*csipb.NodeExpandVolumeResponse, error) {
  218. if f.nextErr != nil {
  219. return nil, f.nextErr
  220. }
  221. if req.GetVolumeId() == "" {
  222. return nil, errors.New("missing volume id")
  223. }
  224. if req.GetVolumePath() == "" {
  225. return nil, errors.New("missing volume path")
  226. }
  227. if req.GetCapacityRange().RequiredBytes <= 0 {
  228. return nil, errors.New("required bytes should be greater than 0")
  229. }
  230. resp := &csipb.NodeExpandVolumeResponse{
  231. CapacityBytes: req.GetCapacityRange().RequiredBytes,
  232. }
  233. return resp, nil
  234. }
  235. // NodeGetId implements csi method
  236. func (f *NodeClient) NodeGetInfo(ctx context.Context, in *csipb.NodeGetInfoRequest, opts ...grpc.CallOption) (*csipb.NodeGetInfoResponse, error) {
  237. if f.nextErr != nil {
  238. return nil, f.nextErr
  239. }
  240. return f.nodeGetInfoResp, nil
  241. }
  242. // NodeGetCapabilities implements csi method
  243. func (f *NodeClient) NodeGetCapabilities(ctx context.Context, in *csipb.NodeGetCapabilitiesRequest, opts ...grpc.CallOption) (*csipb.NodeGetCapabilitiesResponse, error) {
  244. resp := &csipb.NodeGetCapabilitiesResponse{
  245. Capabilities: []*csipb.NodeServiceCapability{},
  246. }
  247. if f.stageUnstageSet {
  248. resp.Capabilities = append(resp.Capabilities, &csipb.NodeServiceCapability{
  249. Type: &csipb.NodeServiceCapability_Rpc{
  250. Rpc: &csipb.NodeServiceCapability_RPC{
  251. Type: csipb.NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME,
  252. },
  253. },
  254. })
  255. }
  256. if f.expansionSet {
  257. resp.Capabilities = append(resp.Capabilities, &csipb.NodeServiceCapability{
  258. Type: &csipb.NodeServiceCapability_Rpc{
  259. Rpc: &csipb.NodeServiceCapability_RPC{
  260. Type: csipb.NodeServiceCapability_RPC_EXPAND_VOLUME,
  261. },
  262. },
  263. })
  264. }
  265. if f.volumeStatsSet {
  266. resp.Capabilities = append(resp.Capabilities, &csipb.NodeServiceCapability{
  267. Type: &csipb.NodeServiceCapability_Rpc{
  268. Rpc: &csipb.NodeServiceCapability_RPC{
  269. Type: csipb.NodeServiceCapability_RPC_GET_VOLUME_STATS,
  270. },
  271. },
  272. })
  273. }
  274. return resp, nil
  275. }
  276. /*
  277. // NodeGetVolumeStats implements csi method
  278. func (f *NodeClient) NodeGetVolumeStats(ctx context.Context, in *csipb.NodeGetVolumeStatsRequest, opts ...grpc.CallOption) (*csipb.NodeGetVolumeStatsResponse, error) {
  279. return nil, nil
  280. }
  281. */
  282. // NodeGetVolumeStats implements csi method
  283. func (f *NodeClient) NodeGetVolumeStats(ctx context.Context, req *csipb.NodeGetVolumeStatsRequest, opts ...grpc.CallOption) (*csipb.NodeGetVolumeStatsResponse, error) {
  284. if f.nextErr != nil {
  285. return nil, f.nextErr
  286. }
  287. if req.GetVolumeId() == "" {
  288. return nil, errors.New("missing volume id")
  289. }
  290. if req.GetVolumePath() == "" {
  291. return nil, errors.New("missing Volume path")
  292. }
  293. if f.nodeVolumeStatsResp != nil {
  294. return f.nodeVolumeStatsResp, nil
  295. }
  296. return &csipb.NodeGetVolumeStatsResponse{}, nil
  297. }
  298. // ControllerClient represents a CSI Controller client
  299. type ControllerClient struct {
  300. nextCapabilities []*csipb.ControllerServiceCapability
  301. nextErr error
  302. }
  303. // NewControllerClient returns a ControllerClient
  304. func NewControllerClient() *ControllerClient {
  305. return &ControllerClient{}
  306. }
  307. // SetNextError injects next expected error
  308. func (f *ControllerClient) SetNextError(err error) {
  309. f.nextErr = err
  310. }
  311. // SetNextCapabilities injects next expected capabilities
  312. func (f *ControllerClient) SetNextCapabilities(caps []*csipb.ControllerServiceCapability) {
  313. f.nextCapabilities = caps
  314. }
  315. // ControllerGetCapabilities implements csi method
  316. func (f *ControllerClient) ControllerGetCapabilities(ctx context.Context, in *csipb.ControllerGetCapabilitiesRequest, opts ...grpc.CallOption) (*csipb.ControllerGetCapabilitiesResponse, error) {
  317. if f.nextErr != nil {
  318. return nil, f.nextErr
  319. }
  320. if f.nextCapabilities == nil {
  321. f.nextCapabilities = []*csipb.ControllerServiceCapability{
  322. {
  323. Type: &csipb.ControllerServiceCapability_Rpc{
  324. Rpc: &csipb.ControllerServiceCapability_RPC{
  325. Type: csipb.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME,
  326. },
  327. },
  328. },
  329. }
  330. }
  331. return &csipb.ControllerGetCapabilitiesResponse{
  332. Capabilities: f.nextCapabilities,
  333. }, nil
  334. }
  335. // CreateVolume implements csi method
  336. func (f *ControllerClient) CreateVolume(ctx context.Context, in *csipb.CreateVolumeRequest, opts ...grpc.CallOption) (*csipb.CreateVolumeResponse, error) {
  337. return nil, nil
  338. }
  339. // DeleteVolume implements csi method
  340. func (f *ControllerClient) DeleteVolume(ctx context.Context, in *csipb.DeleteVolumeRequest, opts ...grpc.CallOption) (*csipb.DeleteVolumeResponse, error) {
  341. return nil, nil
  342. }
  343. // ControllerPublishVolume implements csi method
  344. func (f *ControllerClient) ControllerPublishVolume(ctx context.Context, in *csipb.ControllerPublishVolumeRequest, opts ...grpc.CallOption) (*csipb.ControllerPublishVolumeResponse, error) {
  345. return nil, nil
  346. }
  347. // ControllerUnpublishVolume implements csi method
  348. func (f *ControllerClient) ControllerUnpublishVolume(ctx context.Context, in *csipb.ControllerUnpublishVolumeRequest, opts ...grpc.CallOption) (*csipb.ControllerUnpublishVolumeResponse, error) {
  349. return nil, nil
  350. }
  351. // ValidateVolumeCapabilities implements csi method
  352. func (f *ControllerClient) ValidateVolumeCapabilities(ctx context.Context, in *csipb.ValidateVolumeCapabilitiesRequest, opts ...grpc.CallOption) (*csipb.ValidateVolumeCapabilitiesResponse, error) {
  353. return nil, nil
  354. }
  355. // ListVolumes implements csi method
  356. func (f *ControllerClient) ListVolumes(ctx context.Context, in *csipb.ListVolumesRequest, opts ...grpc.CallOption) (*csipb.ListVolumesResponse, error) {
  357. return nil, nil
  358. }
  359. // GetCapacity implements csi method
  360. func (f *ControllerClient) GetCapacity(ctx context.Context, in *csipb.GetCapacityRequest, opts ...grpc.CallOption) (*csipb.GetCapacityResponse, error) {
  361. return nil, nil
  362. }