github.com/jingruilea/kubeedge@v1.2.0-beta.0.0.20200410162146-4bb8902b3879/cloud/pkg/csidriver/controllerserver.go (about) 1 /* 2 Copyright 2019 The KubeEdge Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package csidriver 18 19 import ( 20 "encoding/base64" 21 "encoding/json" 22 "errors" 23 "fmt" 24 25 "github.com/container-storage-interface/spec/lib/go/csi" 26 "github.com/golang/protobuf/jsonpb" 27 "github.com/pborman/uuid" 28 "golang.org/x/net/context" 29 "google.golang.org/grpc/codes" 30 "google.golang.org/grpc/status" 31 "k8s.io/klog" 32 33 "github.com/kubeedge/beehive/pkg/core/model" 34 "github.com/kubeedge/kubeedge/common/constants" 35 ) 36 37 type controllerServer struct { 38 caps []*csi.ControllerServiceCapability 39 nodeID string 40 kubeEdgeEndpoint string 41 } 42 43 // newControllerServer creates controller server 44 func newControllerServer(nodeID, kubeEdgeEndpoint string) *controllerServer { 45 return &controllerServer{ 46 caps: getControllerServiceCapabilities( 47 []csi.ControllerServiceCapability_RPC_Type{ 48 csi.ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME, 49 csi.ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME, 50 }), 51 nodeID: nodeID, 52 kubeEdgeEndpoint: kubeEdgeEndpoint, 53 } 54 } 55 56 // CreateVolume issues create volume func 57 func (cs *controllerServer) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest) (*csi.CreateVolumeResponse, error) { 58 // Check arguments 59 if len(req.GetName()) == 0 { 60 return nil, status.Error(codes.InvalidArgument, "Name missing in request") 61 } 62 caps := req.GetVolumeCapabilities() 63 if caps == nil { 64 return nil, status.Error(codes.InvalidArgument, "Volume Capabilities missing in request") 65 } 66 67 volumeID := uuid.NewUUID().String() 68 69 // Build message struct 70 msg := model.NewMessage("") 71 resource, err := buildResource(cs.nodeID, 72 DefaultNamespace, 73 constants.CSIResourceTypeVolume, 74 volumeID) 75 if err != nil { 76 klog.Errorf("build message resource failed with error: %s", err) 77 return nil, err 78 } 79 80 m := jsonpb.Marshaler{} 81 js, err := m.MarshalToString(req) 82 if err != nil { 83 klog.Errorf("failed to marshal to string with error: %s", err) 84 return nil, err 85 } 86 klog.V(4).Infof("create volume marshal to string: %s", js) 87 msg.Content = js 88 msg.BuildRouter(DefaultReceiveModuleName, 89 GroupResource, 90 resource, 91 constants.CSIOperationTypeCreateVolume) 92 93 // Marshal message 94 reqData, err := json.Marshal(msg) 95 if err != nil { 96 klog.Errorf("marshal request failed with error: %v", err) 97 return nil, err 98 } 99 100 // Send message to KubeEdge 101 resdata, err := sendToKubeEdge(string(reqData), cs.kubeEdgeEndpoint) 102 if err != nil { 103 klog.Errorf("send to kubeedge failed with error: %v", err) 104 return nil, err 105 } 106 107 // Unmarshal message 108 result, err := extractMessage(resdata) 109 if err != nil { 110 klog.Errorf("unmarshal response failed with error: %v", err) 111 return nil, err 112 } 113 114 klog.V(4).Infof("create volume result: %v", result) 115 data := result.GetContent().(string) 116 117 if msg.GetOperation() == model.ResponseErrorOperation { 118 klog.Errorf("create volume with error: %s", data) 119 return nil, errors.New(data) 120 } 121 122 decodeBytes, err := base64.StdEncoding.DecodeString(data) 123 if err != nil { 124 klog.Errorf("create volume decode with error: %v", err) 125 return nil, err 126 } 127 128 response := &csi.CreateVolumeResponse{} 129 err = json.Unmarshal([]byte(decodeBytes), response) 130 if err != nil { 131 klog.Errorf("create volume unmarshal with error: %v", err) 132 return nil, nil 133 } 134 klog.V(4).Infof("create volume response: %v", response) 135 136 createVolumeResponse := &csi.CreateVolumeResponse{ 137 Volume: &csi.Volume{ 138 VolumeId: response.Volume.VolumeId, 139 CapacityBytes: req.GetCapacityRange().GetRequiredBytes(), 140 VolumeContext: req.GetParameters(), 141 }, 142 } 143 if req.GetVolumeContentSource() != nil { 144 createVolumeResponse.Volume.ContentSource = req.GetVolumeContentSource() 145 } 146 return createVolumeResponse, nil 147 } 148 149 // DeleteVolume issues delete volume func 150 func (cs *controllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest) (*csi.DeleteVolumeResponse, error) { 151 // Check arguments 152 if len(req.GetVolumeId()) == 0 { 153 return nil, status.Error(codes.InvalidArgument, "Volume ID missing in request") 154 } 155 156 // Build message struct 157 msg := model.NewMessage("") 158 resource, err := buildResource(cs.nodeID, 159 DefaultNamespace, 160 constants.CSIResourceTypeVolume, 161 req.GetVolumeId()) 162 if err != nil { 163 klog.Errorf("build message resource failed with error: %s", err) 164 return nil, err 165 } 166 167 m := jsonpb.Marshaler{} 168 js, err := m.MarshalToString(req) 169 if err != nil { 170 klog.Errorf("failed to marshal to string with error: %s", err) 171 return nil, err 172 } 173 klog.V(4).Infof("delete volume marshal to string: %s", js) 174 msg.Content = js 175 msg.BuildRouter(DefaultReceiveModuleName, 176 GroupResource, 177 resource, 178 constants.CSIOperationTypeDeleteVolume) 179 180 // Marshal message 181 reqData, err := json.Marshal(msg) 182 if err != nil { 183 klog.Errorf("marshal request failed with error: %v", err) 184 return nil, err 185 } 186 187 // Send message to KubeEdge 188 resdata, err := sendToKubeEdge(string(reqData), cs.kubeEdgeEndpoint) 189 if err != nil { 190 klog.Errorf("send to kubeedge failed with error: %v", err) 191 return nil, err 192 } 193 194 // Unmarshal message 195 result, err := extractMessage(resdata) 196 if err != nil { 197 klog.Errorf("unmarshal response failed with error: %v", err) 198 return nil, err 199 } 200 201 klog.V(4).Infof("delete volume result: %v", result) 202 data := result.GetContent().(string) 203 204 if msg.GetOperation() == model.ResponseErrorOperation { 205 klog.Errorf("delete volume with error: %s", data) 206 return nil, errors.New(data) 207 } 208 209 decodeBytes, err := base64.StdEncoding.DecodeString(data) 210 if err != nil { 211 klog.Errorf("delete volume decode with error: %v", err) 212 return nil, err 213 } 214 215 deleteVolumeResponse := &csi.DeleteVolumeResponse{} 216 err = json.Unmarshal([]byte(decodeBytes), deleteVolumeResponse) 217 if err != nil { 218 klog.Errorf("delete volume unmarshal with error: %v", err) 219 return nil, nil 220 } 221 klog.V(4).Infof("delete volume response: %v", deleteVolumeResponse) 222 return deleteVolumeResponse, nil 223 } 224 225 // ControllerPublishVolume issues controller publish volume func 226 func (cs *controllerServer) ControllerPublishVolume(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { 227 instanceID := req.GetNodeId() 228 volumeID := req.GetVolumeId() 229 230 if len(volumeID) == 0 { 231 return nil, status.Error(codes.InvalidArgument, "ControllerPublishVolume Volume ID must be provided") 232 } 233 234 if len(instanceID) == 0 { 235 return nil, status.Error(codes.InvalidArgument, "ControllerPublishVolume Instance ID must be provided") 236 } 237 238 // Build message struct 239 msg := model.NewMessage("") 240 resource, err := buildResource(cs.nodeID, 241 DefaultNamespace, 242 constants.CSIResourceTypeVolume, 243 volumeID) 244 if err != nil { 245 klog.Errorf("build message resource failed with error: %s", err) 246 return nil, err 247 } 248 249 m := jsonpb.Marshaler{} 250 js, err := m.MarshalToString(req) 251 if err != nil { 252 klog.Errorf("failed to marshal to string with error: %s", err) 253 return nil, err 254 } 255 klog.V(4).Infof("controller publish volume marshal to string: %s", js) 256 msg.Content = js 257 msg.BuildRouter(DefaultReceiveModuleName, 258 GroupResource, 259 resource, 260 constants.CSIOperationTypeControllerPublishVolume) 261 262 // Marshal message 263 reqData, err := json.Marshal(msg) 264 if err != nil { 265 klog.Errorf("marshal request failed with error: %v", err) 266 return nil, err 267 } 268 269 // Send message to KubeEdge 270 resdata, err := sendToKubeEdge(string(reqData), cs.kubeEdgeEndpoint) 271 if err != nil { 272 klog.Errorf("send to kubeedge failed with error: %v", err) 273 return nil, err 274 } 275 276 // Unmarshal message 277 result, err := extractMessage(resdata) 278 if err != nil { 279 klog.Errorf("unmarshal response failed with error: %v", err) 280 return nil, err 281 } 282 283 klog.V(4).Infof("controller publish volume result: %v", result) 284 data := result.GetContent().(string) 285 286 if msg.GetOperation() == model.ResponseErrorOperation { 287 klog.Errorf("controller publish volume with error: %s", data) 288 return nil, errors.New(data) 289 } 290 291 decodeBytes, err := base64.StdEncoding.DecodeString(data) 292 if err != nil { 293 klog.Errorf("controller publish volume decode with error: %v", err) 294 return nil, err 295 } 296 297 controllerPublishVolumeResponse := &csi.ControllerPublishVolumeResponse{} 298 err = json.Unmarshal([]byte(decodeBytes), controllerPublishVolumeResponse) 299 if err != nil { 300 klog.Errorf("controller publish volume unmarshal with error: %v", err) 301 return nil, nil 302 } 303 klog.V(4).Infof("controller publish volume response: %v", controllerPublishVolumeResponse) 304 return controllerPublishVolumeResponse, nil 305 } 306 307 // ControllerUnpublishVolume issues controller unpublish volume func 308 func (cs *controllerServer) ControllerUnpublishVolume(ctx context.Context, req *csi.ControllerUnpublishVolumeRequest) (*csi.ControllerUnpublishVolumeResponse, error) { 309 instanceID := req.GetNodeId() 310 volumeID := req.GetVolumeId() 311 312 if len(volumeID) == 0 { 313 return nil, status.Error(codes.InvalidArgument, "ControllerUnpublishVolume Volume ID must be provided") 314 } 315 316 if len(instanceID) == 0 { 317 return nil, status.Error(codes.InvalidArgument, "ControllerUnpublishVolume Instance ID must be provided") 318 } 319 320 // Build message struct 321 msg := model.NewMessage("") 322 resource, err := buildResource(cs.nodeID, 323 DefaultNamespace, 324 constants.CSIResourceTypeVolume, 325 volumeID) 326 if err != nil { 327 klog.Errorf("Build message resource failed with error: %s", err) 328 return nil, err 329 } 330 331 m := jsonpb.Marshaler{} 332 js, err := m.MarshalToString(req) 333 if err != nil { 334 klog.Errorf("failed to marshal to string with error: %s", err) 335 return nil, err 336 } 337 klog.V(4).Infof("controller Unpublish Volume marshal to string: %s", js) 338 msg.Content = js 339 msg.BuildRouter(DefaultReceiveModuleName, 340 GroupResource, 341 resource, 342 constants.CSIOperationTypeControllerUnpublishVolume) 343 344 // Marshal message 345 reqData, err := json.Marshal(msg) 346 if err != nil { 347 klog.Errorf("marshal request failed with error: %v", err) 348 return nil, err 349 } 350 351 // Send message to KubeEdge 352 resdata, err := sendToKubeEdge(string(reqData), cs.kubeEdgeEndpoint) 353 if err != nil { 354 klog.Errorf("send to kubeedge failed with error: %v", err) 355 return nil, err 356 } 357 358 // Unmarshal message 359 result, err := extractMessage(resdata) 360 if err != nil { 361 klog.Errorf("unmarshal response failed with error: %v", err) 362 return nil, err 363 } 364 365 klog.V(4).Infof("controller Unpublish Volume result: %v", result) 366 data := result.GetContent().(string) 367 368 if msg.GetOperation() == model.ResponseErrorOperation { 369 klog.Errorf("controller Unpublish Volume with error: %s", data) 370 return nil, errors.New(data) 371 } 372 373 decodeBytes, err := base64.StdEncoding.DecodeString(data) 374 if err != nil { 375 klog.Errorf("controller Unpublish Volume decode with error: %v", err) 376 return nil, err 377 } 378 379 controllerUnpublishVolumeResponse := &csi.ControllerUnpublishVolumeResponse{} 380 err = json.Unmarshal([]byte(decodeBytes), controllerUnpublishVolumeResponse) 381 if err != nil { 382 klog.Errorf("controller Unpublish Volume unmarshal with error: %v", err) 383 return nil, nil 384 } 385 klog.V(4).Infof("controller Unpublish Volume response: %v", controllerUnpublishVolumeResponse) 386 return controllerUnpublishVolumeResponse, nil 387 } 388 389 func (cs *controllerServer) ValidateVolumeCapabilities(ctx context.Context, req *csi.ValidateVolumeCapabilitiesRequest) (*csi.ValidateVolumeCapabilitiesResponse, error) { 390 // Check arguments 391 if len(req.GetVolumeId()) == 0 { 392 return nil, status.Error(codes.InvalidArgument, "Volume ID cannot be empty") 393 } 394 if len(req.VolumeCapabilities) == 0 { 395 return nil, status.Error(codes.InvalidArgument, req.VolumeId) 396 } 397 398 for _, cap := range req.GetVolumeCapabilities() { 399 if cap.GetMount() == nil && cap.GetBlock() == nil { 400 return nil, status.Error(codes.InvalidArgument, "cannot have both mount and block access type be undefined") 401 } 402 } 403 404 return &csi.ValidateVolumeCapabilitiesResponse{ 405 Confirmed: &csi.ValidateVolumeCapabilitiesResponse_Confirmed{ 406 VolumeContext: req.GetVolumeContext(), 407 VolumeCapabilities: req.GetVolumeCapabilities(), 408 Parameters: req.GetParameters(), 409 }, 410 }, nil 411 } 412 413 func (cs *controllerServer) ControllerGetCapabilities(ctx context.Context, req *csi.ControllerGetCapabilitiesRequest) (*csi.ControllerGetCapabilitiesResponse, error) { 414 return &csi.ControllerGetCapabilitiesResponse{ 415 Capabilities: cs.caps, 416 }, nil 417 } 418 419 func getControllerServiceCapabilities(cl []csi.ControllerServiceCapability_RPC_Type) []*csi.ControllerServiceCapability { 420 var csc []*csi.ControllerServiceCapability 421 422 for _, cap := range cl { 423 klog.V(4).Infof("Enabling controller service capability: %v", cap.String()) 424 csc = append(csc, &csi.ControllerServiceCapability{ 425 Type: &csi.ControllerServiceCapability_Rpc{ 426 Rpc: &csi.ControllerServiceCapability_RPC{ 427 Type: cap, 428 }, 429 }, 430 }) 431 } 432 433 return csc 434 } 435 436 func (cs *controllerServer) GetCapacity(ctx context.Context, req *csi.GetCapacityRequest) (*csi.GetCapacityResponse, error) { 437 return nil, status.Error(codes.Unimplemented, "") 438 } 439 440 func (cs *controllerServer) ListVolumes(ctx context.Context, req *csi.ListVolumesRequest) (*csi.ListVolumesResponse, error) { 441 return nil, status.Error(codes.Unimplemented, "") 442 } 443 444 func (cs *controllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error) { 445 return nil, status.Error(codes.Unimplemented, fmt.Sprintf("ControllerExpandVolume is not yet implemented")) 446 } 447 448 func (cs *controllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error) { 449 return nil, status.Error(codes.Unimplemented, fmt.Sprintf("CreateSnapshot is not yet implemented")) 450 } 451 452 func (cs *controllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error) { 453 return nil, status.Error(codes.Unimplemented, fmt.Sprintf("DeleteSnapshot is not yet implemented")) 454 } 455 456 func (cs *controllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error) { 457 return nil, status.Error(codes.Unimplemented, fmt.Sprintf("ListSnapshots is not yet implemented")) 458 }