github.com/Iqoqo/consul@v1.4.5/agent/agent_endpoint.go (about)

     1  package agent
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"log"
     8  	"net"
     9  	"net/http"
    10  	"path/filepath"
    11  	"strconv"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/mitchellh/mapstructure"
    16  
    17  	"github.com/hashicorp/go-memdb"
    18  	"github.com/mitchellh/hashstructure"
    19  
    20  	"github.com/hashicorp/consul/acl"
    21  	cachetype "github.com/hashicorp/consul/agent/cache-types"
    22  	"github.com/hashicorp/consul/agent/checks"
    23  	"github.com/hashicorp/consul/agent/config"
    24  	"github.com/hashicorp/consul/agent/debug"
    25  	"github.com/hashicorp/consul/agent/local"
    26  	"github.com/hashicorp/consul/agent/structs"
    27  	token_store "github.com/hashicorp/consul/agent/token"
    28  	"github.com/hashicorp/consul/api"
    29  	"github.com/hashicorp/consul/ipaddr"
    30  	"github.com/hashicorp/consul/lib"
    31  	"github.com/hashicorp/consul/lib/file"
    32  	"github.com/hashicorp/consul/logger"
    33  	"github.com/hashicorp/consul/types"
    34  	"github.com/hashicorp/logutils"
    35  	"github.com/hashicorp/serf/coordinate"
    36  	"github.com/hashicorp/serf/serf"
    37  	"github.com/prometheus/client_golang/prometheus"
    38  	"github.com/prometheus/client_golang/prometheus/promhttp"
    39  )
    40  
    41  type Self struct {
    42  	Config      interface{}
    43  	DebugConfig map[string]interface{}
    44  	Coord       *coordinate.Coordinate
    45  	Member      serf.Member
    46  	Stats       map[string]map[string]string
    47  	Meta        map[string]string
    48  }
    49  
    50  func (s *HTTPServer) AgentSelf(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
    51  	// Fetch the ACL token, if any, and enforce agent policy.
    52  	var token string
    53  	s.parseToken(req, &token)
    54  	rule, err := s.agent.resolveToken(token)
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  	if rule != nil && !rule.AgentRead(s.agent.config.NodeName) {
    59  		return nil, acl.ErrPermissionDenied
    60  	}
    61  
    62  	var cs lib.CoordinateSet
    63  	if !s.agent.config.DisableCoordinates {
    64  		var err error
    65  		if cs, err = s.agent.GetLANCoordinate(); err != nil {
    66  			return nil, err
    67  		}
    68  	}
    69  
    70  	config := struct {
    71  		Datacenter string
    72  		NodeName   string
    73  		NodeID     string
    74  		Revision   string
    75  		Server     bool
    76  		Version    string
    77  	}{
    78  		Datacenter: s.agent.config.Datacenter,
    79  		NodeName:   s.agent.config.NodeName,
    80  		NodeID:     string(s.agent.config.NodeID),
    81  		Revision:   s.agent.config.Revision,
    82  		Server:     s.agent.config.ServerMode,
    83  		Version:    s.agent.config.Version,
    84  	}
    85  	return Self{
    86  		Config:      config,
    87  		DebugConfig: s.agent.config.Sanitized(),
    88  		Coord:       cs[s.agent.config.SegmentName],
    89  		Member:      s.agent.LocalMember(),
    90  		Stats:       s.agent.Stats(),
    91  		Meta:        s.agent.State.Metadata(),
    92  	}, nil
    93  }
    94  
    95  // enablePrometheusOutput will look for Prometheus mime-type or format Query parameter the same way as Nomad
    96  func enablePrometheusOutput(req *http.Request) bool {
    97  	if format := req.URL.Query().Get("format"); format == "prometheus" {
    98  		return true
    99  	}
   100  	return false
   101  }
   102  
   103  func (s *HTTPServer) AgentMetrics(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   104  	// Fetch the ACL token, if any, and enforce agent policy.
   105  	var token string
   106  	s.parseToken(req, &token)
   107  	rule, err := s.agent.resolveToken(token)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  	if rule != nil && !rule.AgentRead(s.agent.config.NodeName) {
   112  		return nil, acl.ErrPermissionDenied
   113  	}
   114  	if enablePrometheusOutput(req) {
   115  		if s.agent.config.Telemetry.PrometheusRetentionTime < 1 {
   116  			resp.WriteHeader(http.StatusUnsupportedMediaType)
   117  			fmt.Fprint(resp, "Prometheus is not enabled since its retention time is not positive")
   118  			return nil, nil
   119  		}
   120  		handlerOptions := promhttp.HandlerOpts{
   121  			ErrorLog:      s.agent.logger,
   122  			ErrorHandling: promhttp.ContinueOnError,
   123  		}
   124  
   125  		handler := promhttp.HandlerFor(prometheus.DefaultGatherer, handlerOptions)
   126  		handler.ServeHTTP(resp, req)
   127  		return nil, nil
   128  	}
   129  	return s.agent.MemSink.DisplayMetrics(resp, req)
   130  }
   131  
   132  func (s *HTTPServer) AgentReload(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   133  	// Fetch the ACL token, if any, and enforce agent policy.
   134  	var token string
   135  	s.parseToken(req, &token)
   136  	rule, err := s.agent.resolveToken(token)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	if rule != nil && !rule.AgentWrite(s.agent.config.NodeName) {
   141  		return nil, acl.ErrPermissionDenied
   142  	}
   143  
   144  	// Trigger the reload
   145  	errCh := make(chan error, 0)
   146  	select {
   147  	case <-s.agent.shutdownCh:
   148  		return nil, fmt.Errorf("Agent was shutdown before reload could be completed")
   149  	case s.agent.reloadCh <- errCh:
   150  	}
   151  
   152  	// Wait for the result of the reload, or for the agent to shutdown
   153  	select {
   154  	case <-s.agent.shutdownCh:
   155  		return nil, fmt.Errorf("Agent was shutdown before reload could be completed")
   156  	case err := <-errCh:
   157  		return nil, err
   158  	}
   159  }
   160  
   161  func buildAgentService(s *structs.NodeService, proxies map[string]*local.ManagedProxy) api.AgentService {
   162  	weights := api.AgentWeights{Passing: 1, Warning: 1}
   163  	if s.Weights != nil {
   164  		if s.Weights.Passing > 0 {
   165  			weights.Passing = s.Weights.Passing
   166  		}
   167  		weights.Warning = s.Weights.Warning
   168  	}
   169  	as := api.AgentService{
   170  		Kind:              api.ServiceKind(s.Kind),
   171  		ID:                s.ID,
   172  		Service:           s.Service,
   173  		Tags:              s.Tags,
   174  		Meta:              s.Meta,
   175  		Port:              s.Port,
   176  		Address:           s.Address,
   177  		EnableTagOverride: s.EnableTagOverride,
   178  		CreateIndex:       s.CreateIndex,
   179  		ModifyIndex:       s.ModifyIndex,
   180  		Weights:           weights,
   181  	}
   182  
   183  	if as.Tags == nil {
   184  		as.Tags = []string{}
   185  	}
   186  	if as.Meta == nil {
   187  		as.Meta = map[string]string{}
   188  	}
   189  	// Attach Unmanaged Proxy config if exists
   190  	if s.Kind == structs.ServiceKindConnectProxy {
   191  		as.Proxy = s.Proxy.ToAPI()
   192  		// DEPRECATED (ProxyDestination) - remove this when removing ProxyDestination
   193  		// Also set the deprecated ProxyDestination
   194  		as.ProxyDestination = as.Proxy.DestinationServiceName
   195  	}
   196  
   197  	// Attach Connect configs if they exist. We use the actual proxy state since
   198  	// that may have had defaults filled in compared to the config that was
   199  	// provided with the service as stored in the NodeService here.
   200  	if proxy, ok := proxies[s.ID+"-proxy"]; ok {
   201  		as.Connect = &api.AgentServiceConnect{
   202  			Proxy: &api.AgentServiceConnectProxy{
   203  				ExecMode:  api.ProxyExecMode(proxy.Proxy.ExecMode.String()),
   204  				Command:   proxy.Proxy.Command,
   205  				Config:    proxy.Proxy.Config,
   206  				Upstreams: proxy.Proxy.Upstreams.ToAPI(),
   207  			},
   208  		}
   209  	} else if s.Connect.Native {
   210  		as.Connect = &api.AgentServiceConnect{
   211  			Native: true,
   212  		}
   213  	}
   214  	return as
   215  }
   216  
   217  func (s *HTTPServer) AgentServices(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   218  	// Fetch the ACL token, if any.
   219  	var token string
   220  	s.parseToken(req, &token)
   221  
   222  	services := s.agent.State.Services()
   223  	if err := s.agent.filterServices(token, &services); err != nil {
   224  		return nil, err
   225  	}
   226  
   227  	proxies := s.agent.State.Proxies()
   228  
   229  	// Convert into api.AgentService since that includes Connect config but so far
   230  	// NodeService doesn't need to internally. They are otherwise identical since
   231  	// that is the struct used in client for reading the one we output here
   232  	// anyway.
   233  	agentSvcs := make(map[string]*api.AgentService)
   234  
   235  	// Use empty list instead of nil
   236  	for id, s := range services {
   237  		agentService := buildAgentService(s, proxies)
   238  		agentSvcs[id] = &agentService
   239  	}
   240  
   241  	return agentSvcs, nil
   242  }
   243  
   244  // GET /v1/agent/service/:service_id
   245  //
   246  // Returns the service definition for a single local services and allows
   247  // blocking watch using hash-based blocking.
   248  func (s *HTTPServer) AgentService(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   249  	// Get the proxy ID. Note that this is the ID of a proxy's service instance.
   250  	id := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/")
   251  
   252  	// DEPRECATED(managed-proxies) - remove this whole hack.
   253  	//
   254  	// Support managed proxies until they are removed entirely. Since built-in
   255  	// proxy will now use this endpoint, in order to not break managed proxies in
   256  	// the interim until they are removed, we need to mirror the default-setting
   257  	// behavior they had. Rather than thread that through this whole method as
   258  	// special cases that need to be unwound later (and duplicate logic in the
   259  	// proxy config endpoint) just defer to that and then translate the response.
   260  	if managedProxy := s.agent.State.Proxy(id); managedProxy != nil {
   261  		// This is for a managed proxy, use the old endpoint's behavior
   262  		req.URL.Path = "/v1/agent/connect/proxy/" + id
   263  		obj, err := s.AgentConnectProxyConfig(resp, req)
   264  		if err != nil {
   265  			return obj, err
   266  		}
   267  		proxyCfg, ok := obj.(*api.ConnectProxyConfig)
   268  		if !ok {
   269  			return nil, errors.New("internal error")
   270  		}
   271  		// These are all set by defaults so type checks are just sanity checks that
   272  		// should never fail.
   273  		port, ok := proxyCfg.Config["bind_port"].(int)
   274  		if !ok || port < 1 {
   275  			return nil, errors.New("invalid proxy config")
   276  		}
   277  		addr, ok := proxyCfg.Config["bind_address"].(string)
   278  		if !ok || addr == "" {
   279  			return nil, errors.New("invalid proxy config")
   280  		}
   281  		localAddr, ok := proxyCfg.Config["local_service_address"].(string)
   282  		if !ok || localAddr == "" {
   283  			return nil, errors.New("invalid proxy config")
   284  		}
   285  		// Old local_service_address was a host:port
   286  		localAddress, localPortRaw, err := net.SplitHostPort(localAddr)
   287  		if err != nil {
   288  			return nil, err
   289  		}
   290  		localPort, err := strconv.Atoi(localPortRaw)
   291  		if err != nil {
   292  			return nil, err
   293  		}
   294  
   295  		reply := &api.AgentService{
   296  			Kind:        api.ServiceKindConnectProxy,
   297  			ID:          proxyCfg.ProxyServiceID,
   298  			Service:     managedProxy.Proxy.ProxyService.Service,
   299  			Port:        port,
   300  			Address:     addr,
   301  			ContentHash: proxyCfg.ContentHash,
   302  			Proxy: &api.AgentServiceConnectProxyConfig{
   303  				DestinationServiceName: proxyCfg.TargetServiceName,
   304  				DestinationServiceID:   proxyCfg.TargetServiceID,
   305  				LocalServiceAddress:    localAddress,
   306  				LocalServicePort:       localPort,
   307  				Config:                 proxyCfg.Config,
   308  				Upstreams:              proxyCfg.Upstreams,
   309  			},
   310  		}
   311  		return reply, nil
   312  	}
   313  
   314  	// Maybe block
   315  	var queryOpts structs.QueryOptions
   316  	if parseWait(resp, req, &queryOpts) {
   317  		// parseWait returns an error itself
   318  		return nil, nil
   319  	}
   320  
   321  	// Parse the token
   322  	var token string
   323  	s.parseToken(req, &token)
   324  
   325  	// Parse hash specially. Eventually this should happen in parseWait and end up
   326  	// in QueryOptions but I didn't want to make very general changes right away.
   327  	hash := req.URL.Query().Get("hash")
   328  
   329  	return s.agentLocalBlockingQuery(resp, hash, &queryOpts,
   330  		func(ws memdb.WatchSet) (string, interface{}, error) {
   331  
   332  			svcState := s.agent.State.ServiceState(id)
   333  			if svcState == nil {
   334  				resp.WriteHeader(http.StatusNotFound)
   335  				fmt.Fprintf(resp, "unknown proxy service ID: %s", id)
   336  				return "", nil, nil
   337  			}
   338  
   339  			svc := svcState.Service
   340  
   341  			// Setup watch on the service
   342  			ws.Add(svcState.WatchCh)
   343  
   344  			// Check ACLs.
   345  			rule, err := s.agent.resolveToken(token)
   346  			if err != nil {
   347  				return "", nil, err
   348  			}
   349  			if rule != nil && !rule.ServiceRead(svc.Service) {
   350  				return "", nil, acl.ErrPermissionDenied
   351  			}
   352  
   353  			var connect *api.AgentServiceConnect
   354  			var proxy *api.AgentServiceConnectProxyConfig
   355  
   356  			if svc.Connect.Native {
   357  				connect = &api.AgentServiceConnect{
   358  					Native: svc.Connect.Native,
   359  				}
   360  			}
   361  
   362  			if svc.Kind == structs.ServiceKindConnectProxy {
   363  				proxy = svc.Proxy.ToAPI()
   364  			}
   365  
   366  			var weights api.AgentWeights
   367  			if svc.Weights != nil {
   368  				err := mapstructure.Decode(svc.Weights, &weights)
   369  				if err != nil {
   370  					return "", nil, err
   371  				}
   372  			}
   373  
   374  			// Calculate the content hash over the response, minus the hash field
   375  			reply := &api.AgentService{
   376  				Kind:              api.ServiceKind(svc.Kind),
   377  				ID:                svc.ID,
   378  				Service:           svc.Service,
   379  				Tags:              svc.Tags,
   380  				Meta:              svc.Meta,
   381  				Port:              svc.Port,
   382  				Address:           svc.Address,
   383  				EnableTagOverride: svc.EnableTagOverride,
   384  				Weights:           weights,
   385  				Proxy:             proxy,
   386  				Connect:           connect,
   387  			}
   388  
   389  			rawHash, err := hashstructure.Hash(reply, nil)
   390  			if err != nil {
   391  				return "", nil, err
   392  			}
   393  
   394  			// Include the ContentHash in the response body
   395  			reply.ContentHash = fmt.Sprintf("%x", rawHash)
   396  
   397  			return reply.ContentHash, reply, nil
   398  		})
   399  }
   400  
   401  func (s *HTTPServer) AgentChecks(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   402  	// Fetch the ACL token, if any.
   403  	var token string
   404  	s.parseToken(req, &token)
   405  
   406  	checks := s.agent.State.Checks()
   407  	if err := s.agent.filterChecks(token, &checks); err != nil {
   408  		return nil, err
   409  	}
   410  
   411  	// Use empty list instead of nil
   412  	for id, c := range checks {
   413  		if c.ServiceTags == nil {
   414  			clone := *c
   415  			clone.ServiceTags = make([]string, 0)
   416  			checks[id] = &clone
   417  		}
   418  	}
   419  
   420  	return checks, nil
   421  }
   422  
   423  func (s *HTTPServer) AgentMembers(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   424  	// Fetch the ACL token, if any.
   425  	var token string
   426  	s.parseToken(req, &token)
   427  
   428  	// Check if the WAN is being queried
   429  	wan := false
   430  	if other := req.URL.Query().Get("wan"); other != "" {
   431  		wan = true
   432  	}
   433  
   434  	segment := req.URL.Query().Get("segment")
   435  	if wan {
   436  		switch segment {
   437  		case "", api.AllSegments:
   438  			// The zero value and the special "give me all members"
   439  			// key are ok, otherwise the argument doesn't apply to
   440  			// the WAN.
   441  		default:
   442  			resp.WriteHeader(http.StatusBadRequest)
   443  			fmt.Fprint(resp, "Cannot provide a segment with wan=true")
   444  			return nil, nil
   445  		}
   446  	}
   447  
   448  	var members []serf.Member
   449  	if wan {
   450  		members = s.agent.WANMembers()
   451  	} else {
   452  		var err error
   453  		if segment == api.AllSegments {
   454  			members, err = s.agent.delegate.LANMembersAllSegments()
   455  		} else {
   456  			members, err = s.agent.delegate.LANSegmentMembers(segment)
   457  		}
   458  		if err != nil {
   459  			return nil, err
   460  		}
   461  	}
   462  	if err := s.agent.filterMembers(token, &members); err != nil {
   463  		return nil, err
   464  	}
   465  	return members, nil
   466  }
   467  
   468  func (s *HTTPServer) AgentJoin(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   469  	// Fetch the ACL token, if any, and enforce agent policy.
   470  	var token string
   471  	s.parseToken(req, &token)
   472  	rule, err := s.agent.resolveToken(token)
   473  	if err != nil {
   474  		return nil, err
   475  	}
   476  	if rule != nil && !rule.AgentWrite(s.agent.config.NodeName) {
   477  		return nil, acl.ErrPermissionDenied
   478  	}
   479  
   480  	// Check if the WAN is being queried
   481  	wan := false
   482  	if other := req.URL.Query().Get("wan"); other != "" {
   483  		wan = true
   484  	}
   485  
   486  	// Get the address
   487  	addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/join/")
   488  	if wan {
   489  		_, err = s.agent.JoinWAN([]string{addr})
   490  	} else {
   491  		_, err = s.agent.JoinLAN([]string{addr})
   492  	}
   493  	return nil, err
   494  }
   495  
   496  func (s *HTTPServer) AgentLeave(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   497  	// Fetch the ACL token, if any, and enforce agent policy.
   498  	var token string
   499  	s.parseToken(req, &token)
   500  	rule, err := s.agent.resolveToken(token)
   501  	if err != nil {
   502  		return nil, err
   503  	}
   504  	if rule != nil && !rule.AgentWrite(s.agent.config.NodeName) {
   505  		return nil, acl.ErrPermissionDenied
   506  	}
   507  
   508  	if err := s.agent.Leave(); err != nil {
   509  		return nil, err
   510  	}
   511  	return nil, s.agent.ShutdownAgent()
   512  }
   513  
   514  func (s *HTTPServer) AgentForceLeave(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   515  	// Fetch the ACL token, if any, and enforce agent policy.
   516  	var token string
   517  	s.parseToken(req, &token)
   518  	rule, err := s.agent.resolveToken(token)
   519  	if err != nil {
   520  		return nil, err
   521  	}
   522  	if rule != nil && !rule.AgentWrite(s.agent.config.NodeName) {
   523  		return nil, acl.ErrPermissionDenied
   524  	}
   525  
   526  	addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/force-leave/")
   527  	return nil, s.agent.ForceLeave(addr)
   528  }
   529  
   530  // syncChanges is a helper function which wraps a blocking call to sync
   531  // services and checks to the server. If the operation fails, we only
   532  // only warn because the write did succeed and anti-entropy will sync later.
   533  func (s *HTTPServer) syncChanges() {
   534  	if err := s.agent.State.SyncChanges(); err != nil {
   535  		s.agent.logger.Printf("[ERR] agent: failed to sync changes: %v", err)
   536  	}
   537  }
   538  
   539  func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   540  	var args structs.CheckDefinition
   541  	// Fixup the type decode of TTL or Interval.
   542  	decodeCB := func(raw interface{}) error {
   543  		return FixupCheckType(raw)
   544  	}
   545  	if err := decodeBody(req, &args, decodeCB); err != nil {
   546  		resp.WriteHeader(http.StatusBadRequest)
   547  		fmt.Fprintf(resp, "Request decode failed: %v", err)
   548  		return nil, nil
   549  	}
   550  
   551  	// Verify the check has a name.
   552  	if args.Name == "" {
   553  		resp.WriteHeader(http.StatusBadRequest)
   554  		fmt.Fprint(resp, "Missing check name")
   555  		return nil, nil
   556  	}
   557  
   558  	if args.Status != "" && !structs.ValidStatus(args.Status) {
   559  		resp.WriteHeader(http.StatusBadRequest)
   560  		fmt.Fprint(resp, "Bad check status")
   561  		return nil, nil
   562  	}
   563  
   564  	// Construct the health check.
   565  	health := args.HealthCheck(s.agent.config.NodeName)
   566  
   567  	// Verify the check type.
   568  	chkType := args.CheckType()
   569  	err := chkType.Validate()
   570  	if err != nil {
   571  		resp.WriteHeader(http.StatusBadRequest)
   572  		fmt.Fprint(resp, fmt.Errorf("Invalid check: %v", err))
   573  		return nil, nil
   574  	}
   575  
   576  	// Get the provided token, if any, and vet against any ACL policies.
   577  	var token string
   578  	s.parseToken(req, &token)
   579  	if err := s.agent.vetCheckRegister(token, health); err != nil {
   580  		return nil, err
   581  	}
   582  
   583  	// Add the check.
   584  	if err := s.agent.AddCheck(health, chkType, true, token, ConfigSourceRemote); err != nil {
   585  		return nil, err
   586  	}
   587  	s.syncChanges()
   588  	return nil, nil
   589  }
   590  
   591  func (s *HTTPServer) AgentDeregisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   592  	checkID := types.CheckID(strings.TrimPrefix(req.URL.Path, "/v1/agent/check/deregister/"))
   593  
   594  	// Get the provided token, if any, and vet against any ACL policies.
   595  	var token string
   596  	s.parseToken(req, &token)
   597  	if err := s.agent.vetCheckUpdate(token, checkID); err != nil {
   598  		return nil, err
   599  	}
   600  
   601  	if err := s.agent.RemoveCheck(checkID, true); err != nil {
   602  		return nil, err
   603  	}
   604  	s.syncChanges()
   605  	return nil, nil
   606  }
   607  
   608  func (s *HTTPServer) AgentCheckPass(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   609  	checkID := types.CheckID(strings.TrimPrefix(req.URL.Path, "/v1/agent/check/pass/"))
   610  	note := req.URL.Query().Get("note")
   611  
   612  	// Get the provided token, if any, and vet against any ACL policies.
   613  	var token string
   614  	s.parseToken(req, &token)
   615  	if err := s.agent.vetCheckUpdate(token, checkID); err != nil {
   616  		return nil, err
   617  	}
   618  
   619  	if err := s.agent.updateTTLCheck(checkID, api.HealthPassing, note); err != nil {
   620  		return nil, err
   621  	}
   622  	s.syncChanges()
   623  	return nil, nil
   624  }
   625  
   626  func (s *HTTPServer) AgentCheckWarn(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   627  	checkID := types.CheckID(strings.TrimPrefix(req.URL.Path, "/v1/agent/check/warn/"))
   628  	note := req.URL.Query().Get("note")
   629  
   630  	// Get the provided token, if any, and vet against any ACL policies.
   631  	var token string
   632  	s.parseToken(req, &token)
   633  	if err := s.agent.vetCheckUpdate(token, checkID); err != nil {
   634  		return nil, err
   635  	}
   636  
   637  	if err := s.agent.updateTTLCheck(checkID, api.HealthWarning, note); err != nil {
   638  		return nil, err
   639  	}
   640  	s.syncChanges()
   641  	return nil, nil
   642  }
   643  
   644  func (s *HTTPServer) AgentCheckFail(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   645  	checkID := types.CheckID(strings.TrimPrefix(req.URL.Path, "/v1/agent/check/fail/"))
   646  	note := req.URL.Query().Get("note")
   647  
   648  	// Get the provided token, if any, and vet against any ACL policies.
   649  	var token string
   650  	s.parseToken(req, &token)
   651  	if err := s.agent.vetCheckUpdate(token, checkID); err != nil {
   652  		return nil, err
   653  	}
   654  
   655  	if err := s.agent.updateTTLCheck(checkID, api.HealthCritical, note); err != nil {
   656  		return nil, err
   657  	}
   658  	s.syncChanges()
   659  	return nil, nil
   660  }
   661  
   662  // checkUpdate is the payload for a PUT to AgentCheckUpdate.
   663  type checkUpdate struct {
   664  	// Status us one of the api.Health* states, "passing", "warning", or
   665  	// "critical".
   666  	Status string
   667  
   668  	// Output is the information to post to the UI for operators as the
   669  	// output of the process that decided to hit the TTL check. This is
   670  	// different from the note field that's associated with the check
   671  	// itself.
   672  	Output string
   673  }
   674  
   675  // AgentCheckUpdate is a PUT-based alternative to the GET-based Pass/Warn/Fail
   676  // APIs.
   677  func (s *HTTPServer) AgentCheckUpdate(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   678  	var update checkUpdate
   679  	if err := decodeBody(req, &update, nil); err != nil {
   680  		resp.WriteHeader(http.StatusBadRequest)
   681  		fmt.Fprintf(resp, "Request decode failed: %v", err)
   682  		return nil, nil
   683  	}
   684  
   685  	switch update.Status {
   686  	case api.HealthPassing:
   687  	case api.HealthWarning:
   688  	case api.HealthCritical:
   689  	default:
   690  		resp.WriteHeader(http.StatusBadRequest)
   691  		fmt.Fprintf(resp, "Invalid check status: '%s'", update.Status)
   692  		return nil, nil
   693  	}
   694  
   695  	total := len(update.Output)
   696  	if total > checks.BufSize {
   697  		update.Output = fmt.Sprintf("%s ... (captured %d of %d bytes)",
   698  			update.Output[:checks.BufSize], checks.BufSize, total)
   699  	}
   700  
   701  	checkID := types.CheckID(strings.TrimPrefix(req.URL.Path, "/v1/agent/check/update/"))
   702  
   703  	// Get the provided token, if any, and vet against any ACL policies.
   704  	var token string
   705  	s.parseToken(req, &token)
   706  	if err := s.agent.vetCheckUpdate(token, checkID); err != nil {
   707  		return nil, err
   708  	}
   709  
   710  	if err := s.agent.updateTTLCheck(checkID, update.Status, update.Output); err != nil {
   711  		return nil, err
   712  	}
   713  	s.syncChanges()
   714  	return nil, nil
   715  }
   716  
   717  // agentHealthService Returns Health for a given service ID
   718  func agentHealthService(serviceID string, s *HTTPServer) (int, string, api.HealthChecks) {
   719  	checks := s.agent.State.Checks()
   720  	serviceChecks := make(api.HealthChecks, 0)
   721  	for _, c := range checks {
   722  		if c.ServiceID == serviceID || c.ServiceID == "" {
   723  			// TODO: harmonize struct.HealthCheck and api.HealthCheck (or at least extract conversion function)
   724  			healthCheck := &api.HealthCheck{
   725  				Node:        c.Node,
   726  				CheckID:     string(c.CheckID),
   727  				Name:        c.Name,
   728  				Status:      c.Status,
   729  				Notes:       c.Notes,
   730  				Output:      c.Output,
   731  				ServiceID:   c.ServiceID,
   732  				ServiceName: c.ServiceName,
   733  				ServiceTags: c.ServiceTags,
   734  			}
   735  			serviceChecks = append(serviceChecks, healthCheck)
   736  		}
   737  	}
   738  	status := serviceChecks.AggregatedStatus()
   739  	switch status {
   740  	case api.HealthWarning:
   741  		return http.StatusTooManyRequests, status, serviceChecks
   742  	case api.HealthPassing:
   743  		return http.StatusOK, status, serviceChecks
   744  	default:
   745  		return http.StatusServiceUnavailable, status, serviceChecks
   746  	}
   747  }
   748  
   749  func returnTextPlain(req *http.Request) bool {
   750  	if contentType := req.Header.Get("Accept"); strings.HasPrefix(contentType, "text/plain") {
   751  		return true
   752  	}
   753  	if format := req.URL.Query().Get("format"); format != "" {
   754  		return format == "text"
   755  	}
   756  	return false
   757  }
   758  
   759  // AgentHealthServiceByID return the local Service Health given its ID
   760  func (s *HTTPServer) AgentHealthServiceByID(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   761  	// Pull out the service id (service id since there may be several instance of the same service on this host)
   762  	serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/id/")
   763  	if serviceID == "" {
   764  		return nil, &BadRequestError{Reason: "Missing serviceID"}
   765  	}
   766  	services := s.agent.State.Services()
   767  	proxies := s.agent.State.Proxies()
   768  	for _, service := range services {
   769  		if service.ID == serviceID {
   770  			code, status, healthChecks := agentHealthService(serviceID, s)
   771  			if returnTextPlain(req) {
   772  				return status, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "text/plain"}
   773  			}
   774  			serviceInfo := buildAgentService(service, proxies)
   775  			result := &api.AgentServiceChecksInfo{
   776  				AggregatedStatus: status,
   777  				Checks:           healthChecks,
   778  				Service:          &serviceInfo,
   779  			}
   780  			return result, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "application/json"}
   781  		}
   782  	}
   783  	notFoundReason := fmt.Sprintf("ServiceId %s not found", serviceID)
   784  	if returnTextPlain(req) {
   785  		return notFoundReason, CodeWithPayloadError{StatusCode: http.StatusNotFound, Reason: fmt.Sprintf("ServiceId %s not found", serviceID), ContentType: "application/json"}
   786  	}
   787  	return &api.AgentServiceChecksInfo{
   788  		AggregatedStatus: api.HealthCritical,
   789  		Checks:           nil,
   790  		Service:          nil,
   791  	}, CodeWithPayloadError{StatusCode: http.StatusNotFound, Reason: notFoundReason, ContentType: "application/json"}
   792  }
   793  
   794  // AgentHealthServiceByName return the worse status of all the services with given name on an agent
   795  func (s *HTTPServer) AgentHealthServiceByName(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   796  	// Pull out the service name
   797  	serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/name/")
   798  	if serviceName == "" {
   799  		return nil, &BadRequestError{Reason: "Missing service Name"}
   800  	}
   801  	code := http.StatusNotFound
   802  	status := fmt.Sprintf("ServiceName %s Not Found", serviceName)
   803  	services := s.agent.State.Services()
   804  	result := make([]api.AgentServiceChecksInfo, 0, 16)
   805  	proxies := s.agent.State.Proxies()
   806  	for _, service := range services {
   807  		if service.Service == serviceName {
   808  			scode, sstatus, healthChecks := agentHealthService(service.ID, s)
   809  			serviceInfo := buildAgentService(service, proxies)
   810  			res := api.AgentServiceChecksInfo{
   811  				AggregatedStatus: sstatus,
   812  				Checks:           healthChecks,
   813  				Service:          &serviceInfo,
   814  			}
   815  			result = append(result, res)
   816  			// When service is not found, we ignore it and keep existing HTTP status
   817  			if code == http.StatusNotFound {
   818  				code = scode
   819  				status = sstatus
   820  			}
   821  			// We take the worst of all statuses, so we keep iterating
   822  			// passing: 200 < warning: 429 < critical: 503
   823  			if code < scode {
   824  				code = scode
   825  				status = sstatus
   826  			}
   827  		}
   828  	}
   829  	if returnTextPlain(req) {
   830  		return status, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "text/plain"}
   831  	}
   832  	return result, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "application/json"}
   833  }
   834  
   835  func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
   836  	var args structs.ServiceDefinition
   837  	// Fixup the type decode of TTL or Interval if a check if provided.
   838  	decodeCB := func(raw interface{}) error {
   839  		rawMap, ok := raw.(map[string]interface{})
   840  		if !ok {
   841  			return nil
   842  		}
   843  
   844  		// see https://github.com/hashicorp/consul/pull/3557 why we need this
   845  		// and why we should get rid of it.
   846  		config.TranslateKeys(rawMap, map[string]string{
   847  			"enable_tag_override": "EnableTagOverride",
   848  			// Managed Proxy Config
   849  			"exec_mode": "ExecMode",
   850  			// Proxy Upstreams
   851  			"destination_name":      "DestinationName",
   852  			"destination_type":      "DestinationType",
   853  			"destination_namespace": "DestinationNamespace",
   854  			"local_bind_port":       "LocalBindPort",
   855  			"local_bind_address":    "LocalBindAddress",
   856  			// Proxy Config
   857  			"destination_service_name": "DestinationServiceName",
   858  			"destination_service_id":   "DestinationServiceID",
   859  			"local_service_port":       "LocalServicePort",
   860  			"local_service_address":    "LocalServiceAddress",
   861  			// SidecarService
   862  			"sidecar_service": "SidecarService",
   863  
   864  			// DON'T Recurse into these opaque config maps or we might mangle user's
   865  			// keys. Note empty canonical is a special sentinel to prevent recursion.
   866  			"Meta": "",
   867  			// upstreams is an array but this prevents recursion into config field of
   868  			// any item in the array.
   869  			"Proxy.Config":                   "",
   870  			"Proxy.Upstreams.Config":         "",
   871  			"Connect.Proxy.Config":           "",
   872  			"Connect.Proxy.Upstreams.Config": "",
   873  
   874  			// Same exceptions as above, but for a nested sidecar_service note we use
   875  			// the canonical form SidecarService since that is translated by the time
   876  			// the lookup here happens. Note that sidecar service doesn't support
   877  			// managed proxies (connect.proxy).
   878  			"Connect.SidecarService.Meta":                   "",
   879  			"Connect.SidecarService.Proxy.Config":           "",
   880  			"Connect.SidecarService.Proxy.Upstreams.config": "",
   881  		})
   882  
   883  		for k, v := range rawMap {
   884  			switch strings.ToLower(k) {
   885  			case "check":
   886  				if err := FixupCheckType(v); err != nil {
   887  					return err
   888  				}
   889  			case "checks":
   890  				chkTypes, ok := v.([]interface{})
   891  				if !ok {
   892  					continue
   893  				}
   894  				for _, chkType := range chkTypes {
   895  					if err := FixupCheckType(chkType); err != nil {
   896  						return err
   897  					}
   898  				}
   899  			}
   900  		}
   901  		return nil
   902  	}
   903  	if err := decodeBody(req, &args, decodeCB); err != nil {
   904  		resp.WriteHeader(http.StatusBadRequest)
   905  		fmt.Fprintf(resp, "Request decode failed: %v", err)
   906  		return nil, nil
   907  	}
   908  
   909  	// Verify the service has a name.
   910  	if args.Name == "" {
   911  		resp.WriteHeader(http.StatusBadRequest)
   912  		fmt.Fprint(resp, "Missing service name")
   913  		return nil, nil
   914  	}
   915  
   916  	// Check the service address here and in the catalog RPC endpoint
   917  	// since service registration isn't synchronous.
   918  	if ipaddr.IsAny(args.Address) {
   919  		resp.WriteHeader(http.StatusBadRequest)
   920  		fmt.Fprintf(resp, "Invalid service address")
   921  		return nil, nil
   922  	}
   923  
   924  	// Get the node service.
   925  	ns := args.NodeService()
   926  	if ns.Weights != nil {
   927  		if err := structs.ValidateWeights(ns.Weights); err != nil {
   928  			resp.WriteHeader(http.StatusBadRequest)
   929  			fmt.Fprint(resp, fmt.Errorf("Invalid Weights: %v", err))
   930  			return nil, nil
   931  		}
   932  	}
   933  	if err := structs.ValidateMetadata(ns.Meta, false); err != nil {
   934  		resp.WriteHeader(http.StatusBadRequest)
   935  		fmt.Fprint(resp, fmt.Errorf("Invalid Service Meta: %v", err))
   936  		return nil, nil
   937  	}
   938  
   939  	// Run validation. This is the same validation that would happen on
   940  	// the catalog endpoint so it helps ensure the sync will work properly.
   941  	if err := ns.Validate(); err != nil {
   942  		resp.WriteHeader(http.StatusBadRequest)
   943  		fmt.Fprintf(resp, err.Error())
   944  		return nil, nil
   945  	}
   946  
   947  	// Verify the check type.
   948  	chkTypes, err := args.CheckTypes()
   949  	if err != nil {
   950  		resp.WriteHeader(http.StatusBadRequest)
   951  		fmt.Fprint(resp, fmt.Errorf("Invalid check: %v", err))
   952  		return nil, nil
   953  	}
   954  	for _, check := range chkTypes {
   955  		if check.Status != "" && !structs.ValidStatus(check.Status) {
   956  			resp.WriteHeader(http.StatusBadRequest)
   957  			fmt.Fprint(resp, "Status for checks must 'passing', 'warning', 'critical'")
   958  			return nil, nil
   959  		}
   960  	}
   961  
   962  	// Verify the sidecar check types
   963  	if args.Connect != nil && args.Connect.SidecarService != nil {
   964  		chkTypes, err := args.Connect.SidecarService.CheckTypes()
   965  		if err != nil {
   966  			return nil, &BadRequestError{
   967  				Reason: fmt.Sprintf("Invalid check in sidecar_service: %v", err),
   968  			}
   969  		}
   970  		for _, check := range chkTypes {
   971  			if check.Status != "" && !structs.ValidStatus(check.Status) {
   972  				return nil, &BadRequestError{
   973  					Reason: "Status for checks must 'passing', 'warning', 'critical'",
   974  				}
   975  			}
   976  		}
   977  	}
   978  
   979  	// Get the provided token, if any, and vet against any ACL policies.
   980  	var token string
   981  	s.parseToken(req, &token)
   982  	if err := s.agent.vetServiceRegister(token, ns); err != nil {
   983  		return nil, err
   984  	}
   985  
   986  	// See if we have a sidecar to register too
   987  	sidecar, sidecarChecks, sidecarToken, err := s.agent.sidecarServiceFromNodeService(ns, token)
   988  	if err != nil {
   989  		return nil, &BadRequestError{
   990  			Reason: fmt.Sprintf("Invalid SidecarService: %s", err)}
   991  	}
   992  	if sidecar != nil {
   993  		// Make sure we are allowed to register the sidecar using the token
   994  		// specified (might be specific to sidecar or the same one as the overall
   995  		// request).
   996  		if err := s.agent.vetServiceRegister(sidecarToken, sidecar); err != nil {
   997  			return nil, err
   998  		}
   999  		// We parsed the sidecar registration, now remove it from the NodeService
  1000  		// for the actual service since it's done it's job and we don't want to
  1001  		// persist it in the actual state/catalog. SidecarService is meant to be a
  1002  		// registration syntax sugar so don't propagate it any further.
  1003  		ns.Connect.SidecarService = nil
  1004  	}
  1005  
  1006  	// Get any proxy registrations
  1007  	proxy, err := args.ConnectManagedProxy()
  1008  	if err != nil {
  1009  		resp.WriteHeader(http.StatusBadRequest)
  1010  		fmt.Fprintf(resp, err.Error())
  1011  		return nil, nil
  1012  	}
  1013  
  1014  	// If we have a proxy, verify that we're allowed to add a proxy via the API
  1015  	if proxy != nil && !s.agent.config.ConnectProxyAllowManagedAPIRegistration {
  1016  		return nil, &BadRequestError{
  1017  			Reason: "Managed proxy registration via the API is disallowed."}
  1018  	}
  1019  
  1020  	// Add the service.
  1021  	if err := s.agent.AddService(ns, chkTypes, true, token, ConfigSourceRemote); err != nil {
  1022  		return nil, err
  1023  	}
  1024  	// Add proxy (which will add proxy service so do it before we trigger sync)
  1025  	if proxy != nil {
  1026  		if err := s.agent.AddProxy(proxy, true, false, "", ConfigSourceRemote); err != nil {
  1027  			return nil, err
  1028  		}
  1029  	}
  1030  	// Add sidecar.
  1031  	if sidecar != nil {
  1032  		if err := s.agent.AddService(sidecar, sidecarChecks, true, sidecarToken, ConfigSourceRemote); err != nil {
  1033  			return nil, err
  1034  		}
  1035  	}
  1036  	s.syncChanges()
  1037  	return nil, nil
  1038  }
  1039  
  1040  func (s *HTTPServer) AgentDeregisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1041  	serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/deregister/")
  1042  
  1043  	// Get the provided token, if any, and vet against any ACL policies.
  1044  	var token string
  1045  	s.parseToken(req, &token)
  1046  	if err := s.agent.vetServiceUpdate(token, serviceID); err != nil {
  1047  		return nil, err
  1048  	}
  1049  
  1050  	// Verify this isn't a proxy
  1051  	if s.agent.State.Proxy(serviceID) != nil {
  1052  		return nil, &BadRequestError{
  1053  			Reason: "Managed proxy service cannot be deregistered directly. " +
  1054  				"Deregister the service that has a managed proxy to automatically " +
  1055  				"deregister the managed proxy itself."}
  1056  	}
  1057  
  1058  	if err := s.agent.RemoveService(serviceID, true); err != nil {
  1059  		return nil, err
  1060  	}
  1061  
  1062  	s.syncChanges()
  1063  	return nil, nil
  1064  }
  1065  
  1066  func (s *HTTPServer) AgentServiceMaintenance(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1067  	// Ensure we have a service ID
  1068  	serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/maintenance/")
  1069  	if serviceID == "" {
  1070  		resp.WriteHeader(http.StatusBadRequest)
  1071  		fmt.Fprint(resp, "Missing service ID")
  1072  		return nil, nil
  1073  	}
  1074  
  1075  	// Ensure we have some action
  1076  	params := req.URL.Query()
  1077  	if _, ok := params["enable"]; !ok {
  1078  		resp.WriteHeader(http.StatusBadRequest)
  1079  		fmt.Fprint(resp, "Missing value for enable")
  1080  		return nil, nil
  1081  	}
  1082  
  1083  	raw := params.Get("enable")
  1084  	enable, err := strconv.ParseBool(raw)
  1085  	if err != nil {
  1086  		resp.WriteHeader(http.StatusBadRequest)
  1087  		fmt.Fprintf(resp, "Invalid value for enable: %q", raw)
  1088  		return nil, nil
  1089  	}
  1090  
  1091  	// Get the provided token, if any, and vet against any ACL policies.
  1092  	var token string
  1093  	s.parseToken(req, &token)
  1094  	if err := s.agent.vetServiceUpdate(token, serviceID); err != nil {
  1095  		return nil, err
  1096  	}
  1097  
  1098  	if enable {
  1099  		reason := params.Get("reason")
  1100  		if err = s.agent.EnableServiceMaintenance(serviceID, reason, token); err != nil {
  1101  			resp.WriteHeader(http.StatusNotFound)
  1102  			fmt.Fprint(resp, err.Error())
  1103  			return nil, nil
  1104  		}
  1105  	} else {
  1106  		if err = s.agent.DisableServiceMaintenance(serviceID); err != nil {
  1107  			resp.WriteHeader(http.StatusNotFound)
  1108  			fmt.Fprint(resp, err.Error())
  1109  			return nil, nil
  1110  		}
  1111  	}
  1112  	s.syncChanges()
  1113  	return nil, nil
  1114  }
  1115  
  1116  func (s *HTTPServer) AgentNodeMaintenance(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1117  	// Ensure we have some action
  1118  	params := req.URL.Query()
  1119  	if _, ok := params["enable"]; !ok {
  1120  		resp.WriteHeader(http.StatusBadRequest)
  1121  		fmt.Fprint(resp, "Missing value for enable")
  1122  		return nil, nil
  1123  	}
  1124  
  1125  	raw := params.Get("enable")
  1126  	enable, err := strconv.ParseBool(raw)
  1127  	if err != nil {
  1128  		resp.WriteHeader(http.StatusBadRequest)
  1129  		fmt.Fprintf(resp, "Invalid value for enable: %q", raw)
  1130  		return nil, nil
  1131  	}
  1132  
  1133  	// Get the provided token, if any, and vet against any ACL policies.
  1134  	var token string
  1135  	s.parseToken(req, &token)
  1136  	rule, err := s.agent.resolveToken(token)
  1137  	if err != nil {
  1138  		return nil, err
  1139  	}
  1140  	if rule != nil && !rule.NodeWrite(s.agent.config.NodeName, nil) {
  1141  		return nil, acl.ErrPermissionDenied
  1142  	}
  1143  
  1144  	if enable {
  1145  		s.agent.EnableNodeMaintenance(params.Get("reason"), token)
  1146  	} else {
  1147  		s.agent.DisableNodeMaintenance()
  1148  	}
  1149  	s.syncChanges()
  1150  	return nil, nil
  1151  }
  1152  
  1153  func (s *HTTPServer) AgentMonitor(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1154  	// Fetch the ACL token, if any, and enforce agent policy.
  1155  	var token string
  1156  	s.parseToken(req, &token)
  1157  	rule, err := s.agent.resolveToken(token)
  1158  	if err != nil {
  1159  		return nil, err
  1160  	}
  1161  	if rule != nil && !rule.AgentRead(s.agent.config.NodeName) {
  1162  		return nil, acl.ErrPermissionDenied
  1163  	}
  1164  
  1165  	// Get the provided loglevel.
  1166  	logLevel := req.URL.Query().Get("loglevel")
  1167  	if logLevel == "" {
  1168  		logLevel = "INFO"
  1169  	}
  1170  
  1171  	// Upper case the level since that's required by the filter.
  1172  	logLevel = strings.ToUpper(logLevel)
  1173  
  1174  	// Create a level filter and flusher.
  1175  	filter := logger.LevelFilter()
  1176  	filter.MinLevel = logutils.LogLevel(logLevel)
  1177  	if !logger.ValidateLevelFilter(filter.MinLevel, filter) {
  1178  		resp.WriteHeader(http.StatusBadRequest)
  1179  		fmt.Fprintf(resp, "Unknown log level: %s", filter.MinLevel)
  1180  		return nil, nil
  1181  	}
  1182  	flusher, ok := resp.(http.Flusher)
  1183  	if !ok {
  1184  		return nil, fmt.Errorf("Streaming not supported")
  1185  	}
  1186  
  1187  	// Set up a log handler.
  1188  	handler := &httpLogHandler{
  1189  		filter: filter,
  1190  		logCh:  make(chan string, 512),
  1191  		logger: s.agent.logger,
  1192  	}
  1193  	s.agent.LogWriter.RegisterHandler(handler)
  1194  	defer s.agent.LogWriter.DeregisterHandler(handler)
  1195  	notify := resp.(http.CloseNotifier).CloseNotify()
  1196  
  1197  	// Send header so client can start streaming body
  1198  	resp.WriteHeader(http.StatusOK)
  1199  
  1200  	// 0 byte write is needed before the Flush call so that if we are using
  1201  	// a gzip stream it will go ahead and write out the HTTP response header
  1202  	resp.Write([]byte(""))
  1203  	flusher.Flush()
  1204  
  1205  	// Stream logs until the connection is closed.
  1206  	for {
  1207  		select {
  1208  		case <-notify:
  1209  			s.agent.LogWriter.DeregisterHandler(handler)
  1210  			if handler.droppedCount > 0 {
  1211  				s.agent.logger.Printf("[WARN] agent: Dropped %d logs during monitor request", handler.droppedCount)
  1212  			}
  1213  			return nil, nil
  1214  		case log := <-handler.logCh:
  1215  			fmt.Fprintln(resp, log)
  1216  			flusher.Flush()
  1217  		}
  1218  	}
  1219  }
  1220  
  1221  type httpLogHandler struct {
  1222  	filter       *logutils.LevelFilter
  1223  	logCh        chan string
  1224  	logger       *log.Logger
  1225  	droppedCount int
  1226  }
  1227  
  1228  func (h *httpLogHandler) HandleLog(log string) {
  1229  	// Check the log level
  1230  	if !h.filter.Check([]byte(log)) {
  1231  		return
  1232  	}
  1233  
  1234  	// Do a non-blocking send
  1235  	select {
  1236  	case h.logCh <- log:
  1237  	default:
  1238  		// Just increment a counter for dropped logs to this handler; we can't log now
  1239  		// because the lock is already held by the LogWriter invoking this
  1240  		h.droppedCount++
  1241  	}
  1242  }
  1243  
  1244  func (s *HTTPServer) AgentToken(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1245  	if s.checkACLDisabled(resp, req) {
  1246  		return nil, nil
  1247  	}
  1248  
  1249  	// Fetch the ACL token, if any, and enforce agent policy.
  1250  	var token string
  1251  	s.parseToken(req, &token)
  1252  	rule, err := s.agent.resolveToken(token)
  1253  	if err != nil {
  1254  		return nil, err
  1255  	}
  1256  	if rule != nil && !rule.AgentWrite(s.agent.config.NodeName) {
  1257  		return nil, acl.ErrPermissionDenied
  1258  	}
  1259  
  1260  	// The body is just the token, but it's in a JSON object so we can add
  1261  	// fields to this later if needed.
  1262  	var args api.AgentToken
  1263  	if err := decodeBody(req, &args, nil); err != nil {
  1264  		resp.WriteHeader(http.StatusBadRequest)
  1265  		fmt.Fprintf(resp, "Request decode failed: %v", err)
  1266  		return nil, nil
  1267  	}
  1268  
  1269  	if s.agent.config.ACLEnableTokenPersistence {
  1270  		// we hold the lock around updating the internal token store
  1271  		// as well as persisting the tokens because we don't want to write
  1272  		// into the store to have something else wipe it out before we can
  1273  		// persist everything (like an agent config reload). The token store
  1274  		// lock is only held for those operations so other go routines that
  1275  		// just need to read some token out of the store will not be impacted
  1276  		// any more than they would be without token persistence.
  1277  		s.agent.persistedTokensLock.Lock()
  1278  		defer s.agent.persistedTokensLock.Unlock()
  1279  	}
  1280  
  1281  	// Figure out the target token.
  1282  	target := strings.TrimPrefix(req.URL.Path, "/v1/agent/token/")
  1283  	switch target {
  1284  	case "acl_token", "default":
  1285  		s.agent.tokens.UpdateUserToken(args.Token, token_store.TokenSourceAPI)
  1286  
  1287  	case "acl_agent_token", "agent":
  1288  		s.agent.tokens.UpdateAgentToken(args.Token, token_store.TokenSourceAPI)
  1289  
  1290  	case "acl_agent_master_token", "agent_master":
  1291  		s.agent.tokens.UpdateAgentMasterToken(args.Token, token_store.TokenSourceAPI)
  1292  
  1293  	case "acl_replication_token", "replication":
  1294  		s.agent.tokens.UpdateReplicationToken(args.Token, token_store.TokenSourceAPI)
  1295  
  1296  	default:
  1297  		resp.WriteHeader(http.StatusNotFound)
  1298  		fmt.Fprintf(resp, "Token %q is unknown", target)
  1299  		return nil, nil
  1300  	}
  1301  
  1302  	if s.agent.config.ACLEnableTokenPersistence {
  1303  		tokens := persistedTokens{}
  1304  
  1305  		if tok, source := s.agent.tokens.UserTokenAndSource(); tok != "" && source == token_store.TokenSourceAPI {
  1306  			tokens.Default = tok
  1307  		}
  1308  
  1309  		if tok, source := s.agent.tokens.AgentTokenAndSource(); tok != "" && source == token_store.TokenSourceAPI {
  1310  			tokens.Agent = tok
  1311  		}
  1312  
  1313  		if tok, source := s.agent.tokens.AgentMasterTokenAndSource(); tok != "" && source == token_store.TokenSourceAPI {
  1314  			tokens.AgentMaster = tok
  1315  		}
  1316  
  1317  		if tok, source := s.agent.tokens.ReplicationTokenAndSource(); tok != "" && source == token_store.TokenSourceAPI {
  1318  			tokens.Replication = tok
  1319  		}
  1320  
  1321  		data, err := json.Marshal(tokens)
  1322  		if err != nil {
  1323  			s.agent.logger.Printf("[WARN] agent: failed to persist tokens - %v", err)
  1324  			return nil, fmt.Errorf("Failed to marshal tokens for persistence: %v", err)
  1325  		}
  1326  
  1327  		if err := file.WriteAtomicWithPerms(filepath.Join(s.agent.config.DataDir, tokensPath), data, 0600); err != nil {
  1328  			s.agent.logger.Printf("[WARN] agent: failed to persist tokens - %v", err)
  1329  			return nil, fmt.Errorf("Failed to persist tokens - %v", err)
  1330  		}
  1331  	}
  1332  
  1333  	s.agent.logger.Printf("[INFO] agent: Updated agent's ACL token %q", target)
  1334  	return nil, nil
  1335  }
  1336  
  1337  // AgentConnectCARoots returns the trusted CA roots.
  1338  func (s *HTTPServer) AgentConnectCARoots(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1339  	var args structs.DCSpecificRequest
  1340  	if done := s.parse(resp, req, &args.Datacenter, &args.QueryOptions); done {
  1341  		return nil, nil
  1342  	}
  1343  
  1344  	raw, m, err := s.agent.cache.Get(cachetype.ConnectCARootName, &args)
  1345  	if err != nil {
  1346  		return nil, err
  1347  	}
  1348  	defer setCacheMeta(resp, &m)
  1349  
  1350  	// Add cache hit
  1351  
  1352  	reply, ok := raw.(*structs.IndexedCARoots)
  1353  	if !ok {
  1354  		// This should never happen, but we want to protect against panics
  1355  		return nil, fmt.Errorf("internal error: response type not correct")
  1356  	}
  1357  	defer setMeta(resp, &reply.QueryMeta)
  1358  
  1359  	return *reply, nil
  1360  }
  1361  
  1362  // AgentConnectCALeafCert returns the certificate bundle for a service
  1363  // instance. This supports blocking queries to update the returned bundle.
  1364  func (s *HTTPServer) AgentConnectCALeafCert(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1365  	// Get the service name. Note that this is the name of the service,
  1366  	// not the ID of the service instance.
  1367  	serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/connect/ca/leaf/")
  1368  
  1369  	args := cachetype.ConnectCALeafRequest{
  1370  		Service: serviceName, // Need name not ID
  1371  	}
  1372  	var qOpts structs.QueryOptions
  1373  
  1374  	// Store DC in the ConnectCALeafRequest but query opts separately
  1375  	// Don't resolve a proxy token to a real token that will be
  1376  	// done with a call to verifyProxyToken later along with
  1377  	// other security relevant checks.
  1378  	if done := s.parseWithoutResolvingProxyToken(resp, req, &args.Datacenter, &qOpts); done {
  1379  		return nil, nil
  1380  	}
  1381  	args.MinQueryIndex = qOpts.MinQueryIndex
  1382  	args.MaxQueryTime = qOpts.MaxQueryTime
  1383  
  1384  	// Verify the proxy token. This will check both the local proxy token
  1385  	// as well as the ACL if the token isn't local. The checks done in
  1386  	// verifyProxyToken are still relevant because a leaf cert can be cached
  1387  	// verifying the proxy token matches the service id or that a real
  1388  	// acl token still is valid and has ServiceWrite is necessary or
  1389  	// that cached cert is potentially unprotected.
  1390  	effectiveToken, _, err := s.agent.verifyProxyToken(qOpts.Token, serviceName, "")
  1391  	if err != nil {
  1392  		return nil, err
  1393  	}
  1394  	args.Token = effectiveToken
  1395  
  1396  	raw, m, err := s.agent.cache.Get(cachetype.ConnectCALeafName, &args)
  1397  	if err != nil {
  1398  		return nil, err
  1399  	}
  1400  	defer setCacheMeta(resp, &m)
  1401  
  1402  	reply, ok := raw.(*structs.IssuedCert)
  1403  	if !ok {
  1404  		// This should never happen, but we want to protect against panics
  1405  		return nil, fmt.Errorf("internal error: response type not correct")
  1406  	}
  1407  	setIndex(resp, reply.ModifyIndex)
  1408  
  1409  	return reply, nil
  1410  }
  1411  
  1412  // GET /v1/agent/connect/proxy/:proxy_service_id
  1413  //
  1414  // Returns the local proxy config for the identified proxy. Requires token=
  1415  // param with the correct local ProxyToken (not ACL token).
  1416  func (s *HTTPServer) AgentConnectProxyConfig(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1417  	// Get the proxy ID. Note that this is the ID of a proxy's service instance.
  1418  	id := strings.TrimPrefix(req.URL.Path, "/v1/agent/connect/proxy/")
  1419  
  1420  	// Maybe block
  1421  	var queryOpts structs.QueryOptions
  1422  	if parseWait(resp, req, &queryOpts) {
  1423  		// parseWait returns an error itself
  1424  		return nil, nil
  1425  	}
  1426  
  1427  	// Parse the token - don't resolve a proxy token to a real token
  1428  	// that will be done with a call to verifyProxyToken later along with
  1429  	// other security relevant checks.
  1430  	var token string
  1431  	s.parseTokenWithoutResolvingProxyToken(req, &token)
  1432  
  1433  	// Parse hash specially since it's only this endpoint that uses it currently.
  1434  	// Eventually this should happen in parseWait and end up in QueryOptions but I
  1435  	// didn't want to make very general changes right away.
  1436  	hash := req.URL.Query().Get("hash")
  1437  
  1438  	return s.agentLocalBlockingQuery(resp, hash, &queryOpts,
  1439  		func(ws memdb.WatchSet) (string, interface{}, error) {
  1440  			// Retrieve the proxy specified
  1441  			proxy := s.agent.State.Proxy(id)
  1442  			if proxy == nil {
  1443  				resp.WriteHeader(http.StatusNotFound)
  1444  				fmt.Fprintf(resp, "unknown proxy service ID: %s", id)
  1445  				return "", nil, nil
  1446  			}
  1447  
  1448  			// Lookup the target service as a convenience
  1449  			target := s.agent.State.Service(proxy.Proxy.TargetServiceID)
  1450  			if target == nil {
  1451  				// Not found since this endpoint is only useful for agent-managed proxies so
  1452  				// service missing means the service was deregistered racily with this call.
  1453  				resp.WriteHeader(http.StatusNotFound)
  1454  				fmt.Fprintf(resp, "unknown target service ID: %s", proxy.Proxy.TargetServiceID)
  1455  				return "", nil, nil
  1456  			}
  1457  
  1458  			// Validate the ACL token - because this endpoint uses data local to a single
  1459  			// agent, this function is responsible for all enforcement regarding
  1460  			// protection of the configuration. verifyProxyToken will match the proxies
  1461  			// token to the correct service or in the case of being provide a real ACL
  1462  			// token it will ensure that the requester has ServiceWrite privileges
  1463  			// for this service.
  1464  			_, isProxyToken, err := s.agent.verifyProxyToken(token, target.Service, id)
  1465  			if err != nil {
  1466  				return "", nil, err
  1467  			}
  1468  
  1469  			// Watch the proxy for changes
  1470  			ws.Add(proxy.WatchCh)
  1471  
  1472  			hash, err := hashstructure.Hash(proxy.Proxy, nil)
  1473  			if err != nil {
  1474  				return "", nil, err
  1475  			}
  1476  			contentHash := fmt.Sprintf("%x", hash)
  1477  
  1478  			// Set defaults
  1479  			config, err := s.agent.applyProxyConfigDefaults(proxy.Proxy)
  1480  			if err != nil {
  1481  				return "", nil, err
  1482  			}
  1483  
  1484  			// Only merge in telemetry config from agent if the requested is
  1485  			// authorized with a proxy token. This prevents us leaking potentially
  1486  			// sensitive config like Circonus API token via a public endpoint. Proxy
  1487  			// tokens are only ever generated in-memory and passed via ENV to a child
  1488  			// proxy process so potential for abuse here seems small. This endpoint in
  1489  			// general is only useful for managed proxies now so it should _always_ be
  1490  			// true that auth is via a proxy token but inconvenient for testing if we
  1491  			// lock it down so strictly.
  1492  			if isProxyToken {
  1493  				// Add telemetry config. Copy the global config so we can customize the
  1494  				// prefix.
  1495  				telemetryCfg := s.agent.config.Telemetry
  1496  				telemetryCfg.MetricsPrefix = telemetryCfg.MetricsPrefix + ".proxy." + target.ID
  1497  
  1498  				// First see if the user has specified telemetry
  1499  				if userRaw, ok := config["telemetry"]; ok {
  1500  					// User specified domething, see if it is compatible with agent
  1501  					// telemetry config:
  1502  					var uCfg lib.TelemetryConfig
  1503  					dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
  1504  						Result: &uCfg,
  1505  						// Make sure that if the user passes something that isn't just a
  1506  						// simple override of a valid TelemetryConfig that we fail so that we
  1507  						// don't clobber their custom config.
  1508  						ErrorUnused: true,
  1509  					})
  1510  					if err == nil {
  1511  						if err = dec.Decode(userRaw); err == nil {
  1512  							// It did decode! Merge any unspecified fields from agent config.
  1513  							uCfg.MergeDefaults(&telemetryCfg)
  1514  							config["telemetry"] = uCfg
  1515  						}
  1516  					}
  1517  					// Failed to decode, just keep user's config["telemetry"] verbatim
  1518  					// with no agent merge.
  1519  				} else {
  1520  					// Add agent telemetry config.
  1521  					config["telemetry"] = telemetryCfg
  1522  				}
  1523  			}
  1524  
  1525  			reply := &api.ConnectProxyConfig{
  1526  				ProxyServiceID:    proxy.Proxy.ProxyService.ID,
  1527  				TargetServiceID:   target.ID,
  1528  				TargetServiceName: target.Service,
  1529  				ContentHash:       contentHash,
  1530  				ExecMode:          api.ProxyExecMode(proxy.Proxy.ExecMode.String()),
  1531  				Command:           proxy.Proxy.Command,
  1532  				Config:            config,
  1533  				Upstreams:         proxy.Proxy.Upstreams.ToAPI(),
  1534  			}
  1535  			return contentHash, reply, nil
  1536  		})
  1537  }
  1538  
  1539  type agentLocalBlockingFunc func(ws memdb.WatchSet) (string, interface{}, error)
  1540  
  1541  // agentLocalBlockingQuery performs a blocking query in a generic way against
  1542  // local agent state that has no RPC or raft to back it. It uses `hash` parameter
  1543  // instead of an `index`. The resp is needed to write the `X-Consul-ContentHash`
  1544  // header back on return no Status nor body content is ever written to it.
  1545  func (s *HTTPServer) agentLocalBlockingQuery(resp http.ResponseWriter, hash string,
  1546  	queryOpts *structs.QueryOptions, fn agentLocalBlockingFunc) (interface{}, error) {
  1547  
  1548  	// If we are not blocking we can skip tracking and allocating - nil WatchSet
  1549  	// is still valid to call Add on and will just be a no op.
  1550  	var ws memdb.WatchSet
  1551  	var timeout *time.Timer
  1552  
  1553  	if hash != "" {
  1554  		// TODO(banks) at least define these defaults somewhere in a const. Would be
  1555  		// nice not to duplicate the ones in consul/rpc.go too...
  1556  		wait := queryOpts.MaxQueryTime
  1557  		if wait == 0 {
  1558  			wait = 5 * time.Minute
  1559  		}
  1560  		if wait > 10*time.Minute {
  1561  			wait = 10 * time.Minute
  1562  		}
  1563  		// Apply a small amount of jitter to the request.
  1564  		wait += lib.RandomStagger(wait / 16)
  1565  		timeout = time.NewTimer(wait)
  1566  	}
  1567  
  1568  	for {
  1569  		// Must reset this every loop in case the Watch set is already closed but
  1570  		// hash remains same. In that case we'll need to re-block on ws.Watch()
  1571  		// again.
  1572  		ws = memdb.NewWatchSet()
  1573  		curHash, curResp, err := fn(ws)
  1574  		if err != nil {
  1575  			return curResp, err
  1576  		}
  1577  		// Return immediately if there is no timeout, the hash is different or the
  1578  		// Watch returns true (indicating timeout fired). Note that Watch on a nil
  1579  		// WatchSet immediately returns false which would incorrectly cause this to
  1580  		// loop and repeat again, however we rely on the invariant that ws == nil
  1581  		// IFF timeout == nil in which case the Watch call is never invoked.
  1582  		if timeout == nil || hash != curHash || ws.Watch(timeout.C) {
  1583  			resp.Header().Set("X-Consul-ContentHash", curHash)
  1584  			return curResp, err
  1585  		}
  1586  		// Watch returned false indicating a change was detected, loop and repeat
  1587  		// the callback to load the new value. If agent sync is paused it means
  1588  		// local state is currently being bulk-edited e.g. config reload. In this
  1589  		// case it's likely that local state just got unloaded and may or may not be
  1590  		// reloaded yet. Wait a short amount of time for Sync to resume to ride out
  1591  		// typical config reloads.
  1592  		if syncPauseCh := s.agent.syncPausedCh(); syncPauseCh != nil {
  1593  			select {
  1594  			case <-syncPauseCh:
  1595  			case <-timeout.C:
  1596  			}
  1597  		}
  1598  	}
  1599  }
  1600  
  1601  // AgentConnectAuthorize
  1602  //
  1603  // POST /v1/agent/connect/authorize
  1604  //
  1605  // Note: when this logic changes, consider if the Intention.Check RPC method
  1606  // also needs to be updated.
  1607  func (s *HTTPServer) AgentConnectAuthorize(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1608  	// Fetch the token
  1609  	var token string
  1610  	s.parseToken(req, &token)
  1611  
  1612  	// Decode the request from the request body
  1613  	var authReq structs.ConnectAuthorizeRequest
  1614  	if err := decodeBody(req, &authReq, nil); err != nil {
  1615  		return nil, BadRequestError{fmt.Sprintf("Request decode failed: %v", err)}
  1616  	}
  1617  
  1618  	authz, reason, cacheMeta, err := s.agent.ConnectAuthorize(token, &authReq)
  1619  	if err != nil {
  1620  		return nil, err
  1621  	}
  1622  	setCacheMeta(resp, cacheMeta)
  1623  
  1624  	return &connectAuthorizeResp{
  1625  		Authorized: authz,
  1626  		Reason:     reason,
  1627  	}, nil
  1628  }
  1629  
  1630  // connectAuthorizeResp is the response format/structure for the
  1631  // /v1/agent/connect/authorize endpoint.
  1632  type connectAuthorizeResp struct {
  1633  	Authorized bool   // True if authorized, false if not
  1634  	Reason     string // Reason for the Authorized value (whether true or false)
  1635  }
  1636  
  1637  // AgentHost
  1638  //
  1639  // GET /v1/agent/host
  1640  //
  1641  // Retrieves information about resources available and in-use for the
  1642  // host the agent is running on such as CPU, memory, and disk usage. Requires
  1643  // a operator:read ACL token.
  1644  func (s *HTTPServer) AgentHost(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
  1645  	// Fetch the ACL token, if any, and enforce agent policy.
  1646  	var token string
  1647  	s.parseToken(req, &token)
  1648  	rule, err := s.agent.resolveToken(token)
  1649  	if err != nil {
  1650  		return nil, err
  1651  	}
  1652  
  1653  	if rule != nil && !rule.OperatorRead() {
  1654  		return nil, acl.ErrPermissionDenied
  1655  	}
  1656  
  1657  	return debug.CollectHostInfo(), nil
  1658  }