github.com/janma/nomad@v0.11.3/command/agent/csi_endpoint.go (about)

     1  package agent
     2  
     3  import (
     4  	"net/http"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/nomad/nomad/structs"
     8  )
     9  
    10  func (s *HTTPServer) CSIVolumesRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
    11  	if req.Method != "GET" {
    12  		return nil, CodedError(405, ErrInvalidMethod)
    13  	}
    14  
    15  	// Type filters volume lists to a specific type. When support for non-CSI volumes is
    16  	// introduced, we'll need to dispatch here
    17  	query := req.URL.Query()
    18  	qtype, ok := query["type"]
    19  	if !ok {
    20  		return []*structs.CSIVolListStub{}, nil
    21  	}
    22  	if qtype[0] != "csi" {
    23  		return nil, nil
    24  	}
    25  
    26  	args := structs.CSIVolumeListRequest{}
    27  
    28  	if s.parse(resp, req, &args.Region, &args.QueryOptions) {
    29  		return nil, nil
    30  	}
    31  
    32  	if plugin, ok := query["plugin_id"]; ok {
    33  		args.PluginID = plugin[0]
    34  	}
    35  	if node, ok := query["node_id"]; ok {
    36  		args.NodeID = node[0]
    37  	}
    38  
    39  	var out structs.CSIVolumeListResponse
    40  	if err := s.agent.RPC("CSIVolume.List", &args, &out); err != nil {
    41  		return nil, err
    42  	}
    43  
    44  	setMeta(resp, &out.QueryMeta)
    45  	return out.Volumes, nil
    46  }
    47  
    48  // CSIVolumeSpecificRequest dispatches GET and PUT
    49  func (s *HTTPServer) CSIVolumeSpecificRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
    50  	// Tokenize the suffix of the path to get the volume id
    51  	reqSuffix := strings.TrimPrefix(req.URL.Path, "/v1/volume/csi/")
    52  	tokens := strings.Split(reqSuffix, "/")
    53  	if len(tokens) > 2 || len(tokens) < 1 {
    54  		return nil, CodedError(404, resourceNotFoundErr)
    55  	}
    56  	id := tokens[0]
    57  
    58  	switch req.Method {
    59  	case "GET":
    60  		return s.csiVolumeGet(id, resp, req)
    61  	case "PUT":
    62  		return s.csiVolumePut(id, resp, req)
    63  	case "DELETE":
    64  		return s.csiVolumeDelete(id, resp, req)
    65  	default:
    66  		return nil, CodedError(405, ErrInvalidMethod)
    67  	}
    68  }
    69  
    70  func (s *HTTPServer) csiVolumeGet(id string, resp http.ResponseWriter, req *http.Request) (interface{}, error) {
    71  	args := structs.CSIVolumeGetRequest{
    72  		ID: id,
    73  	}
    74  	if s.parse(resp, req, &args.Region, &args.QueryOptions) {
    75  		return nil, nil
    76  	}
    77  
    78  	var out structs.CSIVolumeGetResponse
    79  	if err := s.agent.RPC("CSIVolume.Get", &args, &out); err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	setMeta(resp, &out.QueryMeta)
    84  	if out.Volume == nil {
    85  		return nil, CodedError(404, "volume not found")
    86  	}
    87  
    88  	// remove sensitive fields, as our redaction mechanism doesn't
    89  	// help serializing here
    90  	out.Volume.Secrets = nil
    91  	out.Volume.MountOptions = nil
    92  	return out.Volume, nil
    93  }
    94  
    95  func (s *HTTPServer) csiVolumePut(id string, resp http.ResponseWriter, req *http.Request) (interface{}, error) {
    96  	if req.Method != "PUT" {
    97  		return nil, CodedError(405, ErrInvalidMethod)
    98  	}
    99  
   100  	args0 := structs.CSIVolumeRegisterRequest{}
   101  	if err := decodeBody(req, &args0); err != nil {
   102  		return err, CodedError(400, err.Error())
   103  	}
   104  
   105  	args := structs.CSIVolumeRegisterRequest{
   106  		Volumes: args0.Volumes,
   107  	}
   108  	s.parseWriteRequest(req, &args.WriteRequest)
   109  
   110  	var out structs.CSIVolumeRegisterResponse
   111  	if err := s.agent.RPC("CSIVolume.Register", &args, &out); err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	setMeta(resp, &out.QueryMeta)
   116  
   117  	return nil, nil
   118  }
   119  
   120  func (s *HTTPServer) csiVolumeDelete(id string, resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   121  	if req.Method != "DELETE" {
   122  		return nil, CodedError(405, ErrInvalidMethod)
   123  	}
   124  
   125  	args := structs.CSIVolumeDeregisterRequest{
   126  		VolumeIDs: []string{id},
   127  	}
   128  	s.parseWriteRequest(req, &args.WriteRequest)
   129  
   130  	var out structs.CSIVolumeDeregisterResponse
   131  	if err := s.agent.RPC("CSIVolume.Deregister", &args, &out); err != nil {
   132  		return nil, err
   133  	}
   134  
   135  	setMeta(resp, &out.QueryMeta)
   136  
   137  	return nil, nil
   138  }
   139  
   140  // CSIPluginsRequest lists CSI plugins
   141  func (s *HTTPServer) CSIPluginsRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   142  	if req.Method != "GET" {
   143  		return nil, CodedError(405, ErrInvalidMethod)
   144  	}
   145  
   146  	// Type filters plugin lists to a specific type. When support for non-CSI plugins is
   147  	// introduced, we'll need to dispatch here
   148  	query := req.URL.Query()
   149  	qtype, ok := query["type"]
   150  	if !ok {
   151  		return []*structs.CSIPluginListStub{}, nil
   152  	}
   153  	if qtype[0] != "csi" {
   154  		return nil, nil
   155  	}
   156  
   157  	args := structs.CSIPluginListRequest{}
   158  
   159  	if s.parse(resp, req, &args.Region, &args.QueryOptions) {
   160  		return nil, nil
   161  	}
   162  
   163  	var out structs.CSIPluginListResponse
   164  	if err := s.agent.RPC("CSIPlugin.List", &args, &out); err != nil {
   165  		return nil, err
   166  	}
   167  
   168  	setMeta(resp, &out.QueryMeta)
   169  	return out.Plugins, nil
   170  }
   171  
   172  // CSIPluginSpecificRequest list the job with CSIInfo
   173  func (s *HTTPServer) CSIPluginSpecificRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   174  	if req.Method != "GET" {
   175  		return nil, CodedError(405, ErrInvalidMethod)
   176  	}
   177  
   178  	// Tokenize the suffix of the path to get the plugin id
   179  	reqSuffix := strings.TrimPrefix(req.URL.Path, "/v1/plugin/csi/")
   180  	tokens := strings.Split(reqSuffix, "/")
   181  	if len(tokens) > 2 || len(tokens) < 1 {
   182  		return nil, CodedError(404, resourceNotFoundErr)
   183  	}
   184  	id := tokens[0]
   185  
   186  	args := structs.CSIPluginGetRequest{ID: id}
   187  	if s.parse(resp, req, &args.Region, &args.QueryOptions) {
   188  		return nil, nil
   189  	}
   190  
   191  	var out structs.CSIPluginGetResponse
   192  	if err := s.agent.RPC("CSIPlugin.Get", &args, &out); err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	setMeta(resp, &out.QueryMeta)
   197  	if out.Plugin == nil {
   198  		return nil, CodedError(404, "plugin not found")
   199  	}
   200  
   201  	return out.Plugin, nil
   202  }