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  }