github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/api/server/router/system/system_routes.go (about)

     1  package system // import "github.com/docker/docker/api/server/router/system"
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net/http"
     8  	"time"
     9  
    10  	"github.com/docker/docker/api/server/httputils"
    11  	"github.com/docker/docker/api/server/router/build"
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/api/types/events"
    14  	"github.com/docker/docker/api/types/filters"
    15  	"github.com/docker/docker/api/types/registry"
    16  	timetypes "github.com/docker/docker/api/types/time"
    17  	"github.com/docker/docker/api/types/versions"
    18  	"github.com/docker/docker/pkg/ioutils"
    19  	pkgerrors "github.com/pkg/errors"
    20  	"github.com/sirupsen/logrus"
    21  	"golang.org/x/sync/errgroup"
    22  )
    23  
    24  func optionsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    25  	w.WriteHeader(http.StatusOK)
    26  	return nil
    27  }
    28  
    29  func (s *systemRouter) pingHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    30  	w.Header().Add("Cache-Control", "no-cache, no-store, must-revalidate")
    31  	w.Header().Add("Pragma", "no-cache")
    32  
    33  	builderVersion := build.BuilderVersion(*s.features)
    34  	if bv := builderVersion; bv != "" {
    35  		w.Header().Set("Builder-Version", string(bv))
    36  	}
    37  	if r.Method == http.MethodHead {
    38  		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
    39  		w.Header().Set("Content-Length", "0")
    40  		return nil
    41  	}
    42  	_, err := w.Write([]byte{'O', 'K'})
    43  	return err
    44  }
    45  
    46  func (s *systemRouter) getInfo(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    47  	info, err := s.backend.SystemInfo()
    48  	if err != nil {
    49  		return err
    50  	}
    51  	if s.cluster != nil {
    52  		info.Swarm = s.cluster.Info()
    53  		info.Warnings = append(info.Warnings, info.Swarm.Warnings...)
    54  	}
    55  
    56  	if versions.LessThan(httputils.VersionFromContext(ctx), "1.25") {
    57  		// TODO: handle this conversion in engine-api
    58  		type oldInfo struct {
    59  			*types.Info
    60  			ExecutionDriver string
    61  		}
    62  		old := &oldInfo{
    63  			Info:            info,
    64  			ExecutionDriver: "<not supported>",
    65  		}
    66  		nameOnlySecurityOptions := []string{}
    67  		kvSecOpts, err := types.DecodeSecurityOptions(old.SecurityOptions)
    68  		if err != nil {
    69  			return err
    70  		}
    71  		for _, s := range kvSecOpts {
    72  			nameOnlySecurityOptions = append(nameOnlySecurityOptions, s.Name)
    73  		}
    74  		old.SecurityOptions = nameOnlySecurityOptions
    75  		return httputils.WriteJSON(w, http.StatusOK, old)
    76  	}
    77  	if versions.LessThan(httputils.VersionFromContext(ctx), "1.39") {
    78  		if info.KernelVersion == "" {
    79  			info.KernelVersion = "<unknown>"
    80  		}
    81  		if info.OperatingSystem == "" {
    82  			info.OperatingSystem = "<unknown>"
    83  		}
    84  	}
    85  	return httputils.WriteJSON(w, http.StatusOK, info)
    86  }
    87  
    88  func (s *systemRouter) getVersion(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    89  	info := s.backend.SystemVersion()
    90  
    91  	return httputils.WriteJSON(w, http.StatusOK, info)
    92  }
    93  
    94  func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    95  	eg, ctx := errgroup.WithContext(ctx)
    96  
    97  	var du *types.DiskUsage
    98  	eg.Go(func() error {
    99  		var err error
   100  		du, err = s.backend.SystemDiskUsage(ctx)
   101  		return err
   102  	})
   103  
   104  	var builderSize int64 // legacy
   105  	eg.Go(func() error {
   106  		var err error
   107  		builderSize, err = s.fscache.DiskUsage(ctx)
   108  		if err != nil {
   109  			return pkgerrors.Wrap(err, "error getting fscache build cache usage")
   110  		}
   111  		return nil
   112  	})
   113  
   114  	var buildCache []*types.BuildCache
   115  	eg.Go(func() error {
   116  		var err error
   117  		buildCache, err = s.builder.DiskUsage(ctx)
   118  		if err != nil {
   119  			return pkgerrors.Wrap(err, "error getting build cache usage")
   120  		}
   121  		return nil
   122  	})
   123  
   124  	if err := eg.Wait(); err != nil {
   125  		return err
   126  	}
   127  
   128  	for _, b := range buildCache {
   129  		builderSize += b.Size
   130  	}
   131  
   132  	du.BuilderSize = builderSize
   133  	du.BuildCache = buildCache
   134  
   135  	return httputils.WriteJSON(w, http.StatusOK, du)
   136  }
   137  
   138  type invalidRequestError struct {
   139  	Err error
   140  }
   141  
   142  func (e invalidRequestError) Error() string {
   143  	return e.Err.Error()
   144  }
   145  
   146  func (e invalidRequestError) InvalidParameter() {}
   147  
   148  func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   149  	if err := httputils.ParseForm(r); err != nil {
   150  		return err
   151  	}
   152  
   153  	since, err := eventTime(r.Form.Get("since"))
   154  	if err != nil {
   155  		return err
   156  	}
   157  	until, err := eventTime(r.Form.Get("until"))
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	var (
   163  		timeout        <-chan time.Time
   164  		onlyPastEvents bool
   165  	)
   166  	if !until.IsZero() {
   167  		if until.Before(since) {
   168  			return invalidRequestError{fmt.Errorf("`since` time (%s) cannot be after `until` time (%s)", r.Form.Get("since"), r.Form.Get("until"))}
   169  		}
   170  
   171  		now := time.Now()
   172  
   173  		onlyPastEvents = until.Before(now)
   174  
   175  		if !onlyPastEvents {
   176  			dur := until.Sub(now)
   177  			timeout = time.After(dur)
   178  		}
   179  	}
   180  
   181  	ef, err := filters.FromJSON(r.Form.Get("filters"))
   182  	if err != nil {
   183  		return err
   184  	}
   185  
   186  	w.Header().Set("Content-Type", "application/json")
   187  	output := ioutils.NewWriteFlusher(w)
   188  	defer output.Close()
   189  	output.Flush()
   190  
   191  	enc := json.NewEncoder(output)
   192  
   193  	buffered, l := s.backend.SubscribeToEvents(since, until, ef)
   194  	defer s.backend.UnsubscribeFromEvents(l)
   195  
   196  	for _, ev := range buffered {
   197  		if err := enc.Encode(ev); err != nil {
   198  			return err
   199  		}
   200  	}
   201  
   202  	if onlyPastEvents {
   203  		return nil
   204  	}
   205  
   206  	for {
   207  		select {
   208  		case ev := <-l:
   209  			jev, ok := ev.(events.Message)
   210  			if !ok {
   211  				logrus.Warnf("unexpected event message: %q", ev)
   212  				continue
   213  			}
   214  			if err := enc.Encode(jev); err != nil {
   215  				return err
   216  			}
   217  		case <-timeout:
   218  			return nil
   219  		case <-ctx.Done():
   220  			logrus.Debug("Client context cancelled, stop sending events")
   221  			return nil
   222  		}
   223  	}
   224  }
   225  
   226  func (s *systemRouter) postAuth(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   227  	var config *types.AuthConfig
   228  	err := json.NewDecoder(r.Body).Decode(&config)
   229  	r.Body.Close()
   230  	if err != nil {
   231  		return err
   232  	}
   233  	status, token, err := s.backend.AuthenticateToRegistry(ctx, config)
   234  	if err != nil {
   235  		return err
   236  	}
   237  	return httputils.WriteJSON(w, http.StatusOK, &registry.AuthenticateOKBody{
   238  		Status:        status,
   239  		IdentityToken: token,
   240  	})
   241  }
   242  
   243  func eventTime(formTime string) (time.Time, error) {
   244  	t, tNano, err := timetypes.ParseTimestamps(formTime, -1)
   245  	if err != nil {
   246  		return time.Time{}, err
   247  	}
   248  	if t == -1 {
   249  		return time.Time{}, nil
   250  	}
   251  	return time.Unix(t, tNano), nil
   252  }