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