github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/nomad/alloc_endpoint.go (about)

     1  package nomad
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/armon/go-metrics"
     7  	"github.com/hashicorp/go-memdb"
     8  	"github.com/hashicorp/nomad/nomad/state"
     9  	"github.com/hashicorp/nomad/nomad/structs"
    10  )
    11  
    12  // Alloc endpoint is used for manipulating allocations
    13  type Alloc struct {
    14  	srv *Server
    15  }
    16  
    17  // List is used to list the allocations in the system
    18  func (a *Alloc) List(args *structs.AllocListRequest, reply *structs.AllocListResponse) error {
    19  	if done, err := a.srv.forward("Alloc.List", args, args, reply); done {
    20  		return err
    21  	}
    22  	defer metrics.MeasureSince([]string{"nomad", "alloc", "list"}, time.Now())
    23  
    24  	// Setup the blocking query
    25  	opts := blockingOptions{
    26  		queryOpts: &args.QueryOptions,
    27  		queryMeta: &reply.QueryMeta,
    28  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
    29  			// Capture all the allocations
    30  			var err error
    31  			var iter memdb.ResultIterator
    32  			if prefix := args.QueryOptions.Prefix; prefix != "" {
    33  				iter, err = state.AllocsByIDPrefix(ws, prefix)
    34  			} else {
    35  				iter, err = state.Allocs(ws)
    36  			}
    37  			if err != nil {
    38  				return err
    39  			}
    40  
    41  			var allocs []*structs.AllocListStub
    42  			for {
    43  				raw := iter.Next()
    44  				if raw == nil {
    45  					break
    46  				}
    47  				alloc := raw.(*structs.Allocation)
    48  				allocs = append(allocs, alloc.Stub())
    49  			}
    50  			reply.Allocations = allocs
    51  
    52  			// Use the last index that affected the jobs table
    53  			index, err := state.Index("allocs")
    54  			if err != nil {
    55  				return err
    56  			}
    57  			reply.Index = index
    58  
    59  			// Set the query response
    60  			a.srv.setQueryMeta(&reply.QueryMeta)
    61  			return nil
    62  		}}
    63  	return a.srv.blockingRPC(&opts)
    64  }
    65  
    66  // GetAlloc is used to lookup a particular allocation
    67  func (a *Alloc) GetAlloc(args *structs.AllocSpecificRequest,
    68  	reply *structs.SingleAllocResponse) error {
    69  	if done, err := a.srv.forward("Alloc.GetAlloc", args, args, reply); done {
    70  		return err
    71  	}
    72  	defer metrics.MeasureSince([]string{"nomad", "alloc", "get_alloc"}, time.Now())
    73  
    74  	// Setup the blocking query
    75  	opts := blockingOptions{
    76  		queryOpts: &args.QueryOptions,
    77  		queryMeta: &reply.QueryMeta,
    78  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
    79  			// Lookup the allocation
    80  			out, err := state.AllocByID(ws, args.AllocID)
    81  			if err != nil {
    82  				return err
    83  			}
    84  
    85  			// Setup the output
    86  			reply.Alloc = out
    87  			if out != nil {
    88  				reply.Index = out.ModifyIndex
    89  			} else {
    90  				// Use the last index that affected the allocs table
    91  				index, err := state.Index("allocs")
    92  				if err != nil {
    93  					return err
    94  				}
    95  				reply.Index = index
    96  			}
    97  
    98  			// Set the query response
    99  			a.srv.setQueryMeta(&reply.QueryMeta)
   100  			return nil
   101  		}}
   102  	return a.srv.blockingRPC(&opts)
   103  }
   104  
   105  // GetAllocs is used to lookup a set of allocations
   106  func (a *Alloc) GetAllocs(args *structs.AllocsGetRequest,
   107  	reply *structs.AllocsGetResponse) error {
   108  	if done, err := a.srv.forward("Alloc.GetAllocs", args, args, reply); done {
   109  		return err
   110  	}
   111  	defer metrics.MeasureSince([]string{"nomad", "alloc", "get_allocs"}, time.Now())
   112  
   113  	allocs := make([]*structs.Allocation, len(args.AllocIDs))
   114  
   115  	// Setup the blocking query. We wait for at least one of the requested
   116  	// allocations to be above the min query index. This guarantees that the
   117  	// server has received that index.
   118  	opts := blockingOptions{
   119  		queryOpts: &args.QueryOptions,
   120  		queryMeta: &reply.QueryMeta,
   121  		run: func(ws memdb.WatchSet, state *state.StateStore) error {
   122  			// Lookup the allocation
   123  			thresholdMet := false
   124  			maxIndex := uint64(0)
   125  			for i, alloc := range args.AllocIDs {
   126  				out, err := state.AllocByID(ws, alloc)
   127  				if err != nil {
   128  					return err
   129  				}
   130  				if out == nil {
   131  					// We don't have the alloc yet
   132  					thresholdMet = false
   133  					break
   134  				}
   135  
   136  				// Store the pointer
   137  				allocs[i] = out
   138  
   139  				// Check if we have passed the minimum index
   140  				if out.ModifyIndex > args.QueryOptions.MinQueryIndex {
   141  					thresholdMet = true
   142  				}
   143  
   144  				if maxIndex < out.ModifyIndex {
   145  					maxIndex = out.ModifyIndex
   146  				}
   147  			}
   148  
   149  			// Setup the output
   150  			if thresholdMet {
   151  				reply.Allocs = allocs
   152  				reply.Index = maxIndex
   153  			} else {
   154  				// Use the last index that affected the nodes table
   155  				index, err := state.Index("allocs")
   156  				if err != nil {
   157  					return err
   158  				}
   159  				reply.Index = index
   160  			}
   161  
   162  			// Set the query response
   163  			a.srv.setQueryMeta(&reply.QueryMeta)
   164  			return nil
   165  		},
   166  	}
   167  	return a.srv.blockingRPC(&opts)
   168  }