small pixel drawing of a pufferfish cascade

ls/members: tabwrite
Jes Olson j3s@c3f.net
Wed, 01 Mar 2023 20:28:34 -0800
commit

932829649d1df3e287417a27563820e92660f40e

parent

d0261388a7c825e4da5a5f2a0ae21848ea434031

4 files changed, 32 insertions(+), 1056 deletions(-)

jump to
M agent/agent_endpoint.goagent/agent_endpoint.go

@@ -29,16 +29,18 @@ Version string

BuildDate string }{ NodeName: s.agent.Config.NodeName, - // We expect the ent version to be part of the reported version string, and that's now part of the metadata, not the actual version. + // We expect the ent version to be part + // of the reported version string, and that's + // now part of the metadata, not the actual version. Version: s.agent.Config.VersionWithMetadata(), } return Self{ Config: config, - // Coord: cs[s.agent.Config.SegmentName], - // Member: s.agent.AgentLocalMember(), - // Stats: s.agent.Stats(), - // Meta: s.agent.State.Metadata(), + // Coord: cs[s.agent.Config.SegmentName], + // Member: s.agent.AgentLocalMember(), + // Stats: s.agent.Stats(), + // Meta: s.agent.State.Metadata(), }, nil }

@@ -52,1049 +54,3 @@ fmt.Println(err)

} fmt.Fprintf(w, string(json)) } - -// func (s *HTTPHandlers) AgentJoin(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Fetch the ACL token, if any, and enforce agent policy. -// var token string -// s.parseToken(req, &token) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) -// if err != nil { -// return nil, err -// } -// -// // Authorize using the agent's own enterprise meta, not the token. -// var authzContext acl.AuthorizerContext -// s.agent.AgentEnterpriseMeta().FillAuthzContext(&authzContext) -// -// if err := authz.ToAllowAuthorizer().AgentWriteAllowed(s.agent.config.NodeName, &authzContext); err != nil { -// return nil, err -// } -// -// // Get the request partition and default to that of the agent. -// entMeta := s.agent.AgentEnterpriseMeta() -// if err := s.parseEntMetaPartition(req, entMeta); err != nil { -// return nil, err -// } -// -// // Check if the WAN is being queried -// wan := false -// if other := req.URL.Query().Get("wan"); other != "" { -// wan = true -// } -// -// // Get the address -// addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/join/") -// -// if wan { -// if s.agent.config.ConnectMeshGatewayWANFederationEnabled { -// return nil, fmt.Errorf("WAN join is disabled when wan federation via mesh gateways is enabled") -// } -// _, err = s.agent.JoinWAN([]string{addr}) -// } else { -// _, err = s.agent.JoinLAN([]string{addr}, entMeta) -// } -// return nil, err -// } -// -// func (s *HTTPHandlers) AgentLeave(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Fetch the ACL token, if any, and enforce agent policy. -// var token string -// s.parseToken(req, &token) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) -// if err != nil { -// return nil, err -// } -// -// // Authorize using the agent's own enterprise meta, not the token. -// var authzContext acl.AuthorizerContext -// s.agent.AgentEnterpriseMeta().FillAuthzContext(&authzContext) -// if err := authz.ToAllowAuthorizer().AgentWriteAllowed(s.agent.config.NodeName, &authzContext); err != nil { -// return nil, err -// } -// -// if err := s.agent.Leave(); err != nil { -// return nil, err -// } -// return nil, s.agent.ShutdownAgent() -// } -// -// func (s *HTTPHandlers) AgentForceLeave(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Fetch the ACL token, if any, and enforce agent policy. -// var token string -// s.parseToken(req, &token) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) -// if err != nil { -// return nil, err -// } -// // TODO(partitions): should this be possible in a partition? -// if err := authz.ToAllowAuthorizer().OperatorWriteAllowed(nil); err != nil { -// return nil, err -// } -// -// // Get the request partition and default to that of the agent. -// entMeta := s.agent.AgentEnterpriseMeta() -// if err := s.parseEntMetaPartition(req, entMeta); err != nil { -// return nil, err -// } -// -// // Check the value of the prune query -// _, prune := req.URL.Query()["prune"] -// -// // Check if the WAN is being queried -// _, wan := req.URL.Query()["wan"] -// -// addr := strings.TrimPrefix(req.URL.Path, "/v1/agent/force-leave/") -// if wan { -// return nil, s.agent.ForceLeaveWAN(addr, prune, entMeta) -// } else { -// return nil, s.agent.ForceLeave(addr, prune, entMeta) -// } -// } -// -// // syncChanges is a helper function which wraps a blocking call to sync -// // services and checks to the server. If the operation fails, we only -// // only warn because the write did succeed and anti-entropy will sync later. -// func (s *HTTPHandlers) syncChanges() { -// if err := s.agent.State.SyncChanges(); err != nil { -// s.agent.logger.Error("failed to sync changes", "error", err) -// } -// } -// -// func (s *HTTPHandlers) AgentRegisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// var token string -// s.parseToken(req, &token) -// -// var args structs.CheckDefinition -// if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// if err := decodeBody(req.Body, &args); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Request decode failed: %v", err)} -// } -// -// // Verify the check has a name. -// if args.Name == "" { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing check name"} -// } -// -// if args.Status != "" && !structs.ValidStatus(args.Status) { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Bad check status"} -// } -// -// s.defaultMetaPartitionToAgent(&args.EnterpriseMeta) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &args.EnterpriseMeta, nil) -// if err != nil { -// return nil, err -// } -// -// if !s.validateRequestPartition(resp, &args.EnterpriseMeta) { -// return nil, nil -// } -// -// // Construct the health check. -// health := args.HealthCheck(s.agent.config.NodeName) -// -// // Verify the check type. -// chkType := args.CheckType() -// err = chkType.Validate() -// if err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid check: %v", err)} -// } -// -// // Store the type of check based on the definition -// health.Type = chkType.Type() -// -// if health.ServiceID != "" { -// // fixup the service name so that vetCheckRegister requires the right ACLs -// cid := health.CompoundServiceID() -// service := s.agent.State.Service(cid) -// if service != nil { -// health.ServiceName = service.Service -// } else { -// return nil, HTTPError{StatusCode: http.StatusNotFound, Reason: fmt.Sprintf("ServiceID %q does not exist", cid.String())} -// } -// } -// -// // Get the provided token, if any, and vet against any ACL policies. -// if err := s.agent.vetCheckRegisterWithAuthorizer(authz, health); err != nil { -// return nil, err -// } -// -// // Add the check. -// if err := s.agent.AddCheck(health, chkType, true, token, ConfigSourceRemote); err != nil { -// return nil, err -// } -// s.syncChanges() -// return nil, nil -// } -// -// func (s *HTTPHandlers) AgentDeregisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/deregister/") -// -// entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") -// checkID := structs.NewCheckID(types.CheckID(id), &entMeta) -// -// // Get the provided token, if any, and vet against any ACL policies. -// var token string -// s.parseToken(req, &token) -// -// if err := s.parseEntMetaNoWildcard(req, &checkID.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &checkID.EnterpriseMeta, nil) -// if err != nil { -// return nil, err -// } -// -// checkID.Normalize() -// -// if !s.validateRequestPartition(resp, &checkID.EnterpriseMeta) { -// return nil, nil -// } -// -// if err := s.agent.vetCheckUpdateWithAuthorizer(authz, checkID); err != nil { -// return nil, err -// } -// -// if err := s.agent.RemoveCheck(checkID, true); err != nil { -// return nil, err -// } -// s.syncChanges() -// return nil, nil -// } -// -// func (s *HTTPHandlers) AgentCheckPass(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/pass/") -// checkID := types.CheckID(id) -// note := req.URL.Query().Get("note") -// return s.agentCheckUpdate(resp, req, checkID, api.HealthPassing, note) -// } -// -// func (s *HTTPHandlers) AgentCheckWarn(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/warn/") -// checkID := types.CheckID(id) -// note := req.URL.Query().Get("note") -// -// return s.agentCheckUpdate(resp, req, checkID, api.HealthWarning, note) -// -// } -// -// func (s *HTTPHandlers) AgentCheckFail(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/fail/") -// checkID := types.CheckID(id) -// note := req.URL.Query().Get("note") -// -// return s.agentCheckUpdate(resp, req, checkID, api.HealthCritical, note) -// } -// -// // checkUpdate is the payload for a PUT to AgentCheckUpdate. -// type checkUpdate struct { -// // Status us one of the api.Health* states, "passing", "warning", or -// // "critical". -// Status string -// -// // Output is the information to post to the UI for operators as the -// // output of the process that decided to hit the TTL check. This is -// // different from the note field that's associated with the check -// // itself. -// Output string -// } -// -// // AgentCheckUpdate is a PUT-based alternative to the GET-based Pass/Warn/Fail -// // APIs. -// func (s *HTTPHandlers) AgentCheckUpdate(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// var update checkUpdate -// if err := decodeBody(req.Body, &update); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Request decode failed: %v", err)} -// } -// -// switch update.Status { -// case api.HealthPassing: -// case api.HealthWarning: -// case api.HealthCritical: -// default: -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid check status: '%s'", update.Status)} -// } -// -// id := strings.TrimPrefix(req.URL.Path, "/v1/agent/check/update/") -// checkID := types.CheckID(id) -// -// return s.agentCheckUpdate(resp, req, checkID, update.Status, update.Output) -// } -// -// func (s *HTTPHandlers) agentCheckUpdate(resp http.ResponseWriter, req *http.Request, checkID types.CheckID, status string, output string) (interface{}, error) { -// entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") -// cid := structs.NewCheckID(checkID, &entMeta) -// -// // Get the provided token, if any, and vet against any ACL policies. -// var token string -// s.parseToken(req, &token) -// -// if err := s.parseEntMetaNoWildcard(req, &cid.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &cid.EnterpriseMeta, nil) -// if err != nil { -// return nil, err -// } -// -// cid.Normalize() -// -// if err := s.agent.vetCheckUpdateWithAuthorizer(authz, cid); err != nil { -// return nil, err -// } -// -// if !s.validateRequestPartition(resp, &cid.EnterpriseMeta) { -// return nil, nil -// } -// -// if err := s.agent.updateTTLCheck(cid, status, output); err != nil { -// return nil, err -// } -// s.syncChanges() -// return nil, nil -// } -// -// // agentHealthService Returns Health for a given service ID -// func agentHealthService(serviceID structs.ServiceID, s *HTTPHandlers) (int, string, api.HealthChecks) { -// checks := s.agent.State.ChecksForService(serviceID, true) -// serviceChecks := make(api.HealthChecks, 0) -// for _, c := range checks { -// // TODO: harmonize struct.HealthCheck and api.HealthCheck (or at least extract conversion function) -// healthCheck := &api.HealthCheck{ -// Node: c.Node, -// CheckID: string(c.CheckID), -// Name: c.Name, -// Status: c.Status, -// Notes: c.Notes, -// Output: c.Output, -// ServiceID: c.ServiceID, -// ServiceName: c.ServiceName, -// ServiceTags: c.ServiceTags, -// } -// fillHealthCheckEnterpriseMeta(healthCheck, &c.EnterpriseMeta) -// serviceChecks = append(serviceChecks, healthCheck) -// } -// status := serviceChecks.AggregatedStatus() -// switch status { -// case api.HealthWarning: -// return http.StatusTooManyRequests, status, serviceChecks -// case api.HealthPassing: -// return http.StatusOK, status, serviceChecks -// default: -// return http.StatusServiceUnavailable, status, serviceChecks -// } -// } -// -// func returnTextPlain(req *http.Request) bool { -// if contentType := req.Header.Get("Accept"); strings.HasPrefix(contentType, "text/plain") { -// return true -// } -// if format := req.URL.Query().Get("format"); format != "" { -// return format == "text" -// } -// return false -// } -// -// // AgentHealthServiceByID return the local Service Health given its ID -// func (s *HTTPHandlers) AgentHealthServiceByID(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Pull out the service id (service id since there may be several instance of the same service on this host) -// serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/id/") -// if serviceID == "" { -// return nil, &HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing serviceID"} -// } -// -// var entMeta acl.EnterpriseMeta -// if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil { -// return nil, err -// } -// -// var token string -// s.parseToken(req, &token) -// -// // need to resolve to default the meta -// s.defaultMetaPartitionToAgent(&entMeta) -// var authzContext acl.AuthorizerContext -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &entMeta, &authzContext) -// if err != nil { -// return nil, err -// } -// -// if !s.validateRequestPartition(resp, &entMeta) { -// return nil, nil -// } -// -// sid := structs.NewServiceID(serviceID, &entMeta) -// -// dc := s.agent.config.Datacenter -// -// if service := s.agent.State.Service(sid); service != nil { -// if err := authz.ToAllowAuthorizer().ServiceReadAllowed(service.Service, &authzContext); err != nil { -// return nil, err -// } -// code, status, healthChecks := agentHealthService(sid, s) -// if returnTextPlain(req) { -// return status, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "text/plain"} -// } -// serviceInfo := buildAgentService(service, dc) -// result := &api.AgentServiceChecksInfo{ -// AggregatedStatus: status, -// Checks: healthChecks, -// Service: &serviceInfo, -// } -// return result, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "application/json"} -// } -// notFoundReason := fmt.Sprintf("ServiceId %s not found", sid.String()) -// if returnTextPlain(req) { -// return notFoundReason, CodeWithPayloadError{StatusCode: http.StatusNotFound, Reason: notFoundReason, ContentType: "text/plain"} -// } -// return &api.AgentServiceChecksInfo{ -// AggregatedStatus: api.HealthCritical, -// Checks: nil, -// Service: nil, -// }, CodeWithPayloadError{StatusCode: http.StatusNotFound, Reason: notFoundReason, ContentType: "application/json"} -// } -// -// // AgentHealthServiceByName return the worse status of all the services with given name on an agent -// func (s *HTTPHandlers) AgentHealthServiceByName(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Pull out the service name -// serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/health/service/name/") -// if serviceName == "" { -// return nil, &HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing service Name"} -// } -// -// var entMeta acl.EnterpriseMeta -// if err := s.parseEntMetaNoWildcard(req, &entMeta); err != nil { -// return nil, err -// } -// -// var token string -// s.parseToken(req, &token) -// -// s.defaultMetaPartitionToAgent(&entMeta) -// // need to resolve to default the meta -// var authzContext acl.AuthorizerContext -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &entMeta, &authzContext) -// if err != nil { -// return nil, err -// } -// -// if err := authz.ToAllowAuthorizer().ServiceReadAllowed(serviceName, &authzContext); err != nil { -// return nil, err -// } -// -// if !s.validateRequestPartition(resp, &entMeta) { -// return nil, nil -// } -// -// dc := s.agent.config.Datacenter -// -// code := http.StatusNotFound -// status := fmt.Sprintf("ServiceName %s Not Found", serviceName) -// -// services := s.agent.State.ServicesByName(structs.NewServiceName(serviceName, &entMeta)) -// result := make([]api.AgentServiceChecksInfo, 0, 16) -// for _, service := range services { -// sid := structs.NewServiceID(service.ID, &entMeta) -// -// scode, sstatus, healthChecks := agentHealthService(sid, s) -// serviceInfo := buildAgentService(service, dc) -// res := api.AgentServiceChecksInfo{ -// AggregatedStatus: sstatus, -// Checks: healthChecks, -// Service: &serviceInfo, -// } -// result = append(result, res) -// // When service is not found, we ignore it and keep existing HTTP status -// if code == http.StatusNotFound { -// code = scode -// status = sstatus -// } -// // We take the worst of all statuses, so we keep iterating -// // passing: 200 < warning: 429 < critical: 503 -// if code < scode { -// code = scode -// status = sstatus -// } -// } -// if returnTextPlain(req) { -// return status, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "text/plain"} -// } -// return result, CodeWithPayloadError{StatusCode: code, Reason: status, ContentType: "application/json"} -// } -// -// func (s *HTTPHandlers) AgentRegisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// var args structs.ServiceDefinition -// // Fixup the type decode of TTL or Interval if a check if provided. -// -// if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// if err := decodeBody(req.Body, &args); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Request decode failed: %v", err)} -// } -// -// // Verify the service has a name. -// if args.Name == "" { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing service name"} -// } -// -// // Check the service address here and in the catalog RPC endpoint -// // since service registration isn't synchronous. -// if ipaddr.IsAny(args.Address) { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Invalid service address"} -// } -// -// var token string -// s.parseToken(req, &token) -// -// s.defaultMetaPartitionToAgent(&args.EnterpriseMeta) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &args.EnterpriseMeta, nil) -// if err != nil { -// return nil, err -// } -// -// if !s.validateRequestPartition(resp, &args.EnterpriseMeta) { -// return nil, nil -// } -// -// // Get the node service. -// ns := args.NodeService() -// if ns.Weights != nil { -// if err := structs.ValidateWeights(ns.Weights); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid Weights: %v", err)} -// } -// } -// if err := structs.ValidateServiceMetadata(ns.Kind, ns.Meta, false); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid Service Meta: %v", err)} -// } -// -// // Run validation. This same validation would happen on the catalog endpoint, -// // so it helps ensure the sync will work properly. -// if err := ns.Validate(); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Validation failed: %v", err.Error())} -// } -// -// // Verify the check type. -// chkTypes, err := args.CheckTypes() -// if err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid check: %v", err)} -// } -// for _, check := range chkTypes { -// if check.Status != "" && !structs.ValidStatus(check.Status) { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Status for checks must 'passing', 'warning', 'critical'"} -// } -// } -// -// // Verify the sidecar check types -// if args.Connect != nil && args.Connect.SidecarService != nil { -// chkTypes, err := args.Connect.SidecarService.CheckTypes() -// if err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid check in sidecar_service: %v", err)} -// } -// for _, check := range chkTypes { -// if check.Status != "" && !structs.ValidStatus(check.Status) { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Status for checks must 'passing', 'warning', 'critical'"} -// } -// } -// } -// -// // Get the provided token, if any, and vet against any ACL policies. -// if err := s.agent.vetServiceRegisterWithAuthorizer(authz, ns); err != nil { -// return nil, err -// } -// -// // See if we have a sidecar to register too -// sidecar, sidecarChecks, sidecarToken, err := sidecarServiceFromNodeService(ns, token) -// if err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid SidecarService: %s", err)} -// } -// if sidecar != nil { -// if err := sidecar.ValidateForAgent(); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Failed Validation: %v", err.Error())} -// } -// // Make sure we are allowed to register the sidecar using the token -// // specified (might be specific to sidecar or the same one as the overall -// // request). -// if err := s.agent.vetServiceRegister(sidecarToken, sidecar); err != nil { -// return nil, err -// } -// // We parsed the sidecar registration, now remove it from the NodeService -// // for the actual service since it's done it's job and we don't want to -// // persist it in the actual state/catalog. SidecarService is meant to be a -// // registration syntax sugar so don't propagate it any further. -// ns.Connect.SidecarService = nil -// } -// -// // Add the service. -// replaceExistingChecks := false -// -// query := req.URL.Query() -// if len(query["replace-existing-checks"]) > 0 && (query.Get("replace-existing-checks") == "" || query.Get("replace-existing-checks") == "true") { -// replaceExistingChecks = true -// } -// -// addReq := AddServiceRequest{ -// Service: ns, -// chkTypes: chkTypes, -// persist: true, -// token: token, -// Source: ConfigSourceRemote, -// replaceExistingChecks: replaceExistingChecks, -// } -// if err := s.agent.AddService(addReq); err != nil { -// return nil, err -// } -// -// if sidecar != nil { -// addReq := AddServiceRequest{ -// Service: sidecar, -// chkTypes: sidecarChecks, -// persist: true, -// token: sidecarToken, -// Source: ConfigSourceRemote, -// replaceExistingChecks: replaceExistingChecks, -// } -// if err := s.agent.AddService(addReq); err != nil { -// return nil, err -// } -// } -// s.syncChanges() -// return nil, nil -// } -// -// func (s *HTTPHandlers) AgentDeregisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/deregister/") -// entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") -// sid := structs.NewServiceID(serviceID, &entMeta) -// -// // Get the provided token, if any, and vet against any ACL policies. -// var token string -// s.parseToken(req, &token) -// -// if err := s.parseEntMetaNoWildcard(req, &sid.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &sid.EnterpriseMeta, nil) -// if err != nil { -// return nil, err -// } -// -// sid.Normalize() -// -// if !s.validateRequestPartition(resp, &sid.EnterpriseMeta) { -// return nil, nil -// } -// -// if err := s.agent.vetServiceUpdateWithAuthorizer(authz, sid); err != nil { -// return nil, err -// } -// -// if err := s.agent.RemoveService(sid); err != nil { -// return nil, err -// } -// -// s.syncChanges() -// return nil, nil -// } -// -// func (s *HTTPHandlers) AgentServiceMaintenance(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Ensure we have a service ID -// serviceID := strings.TrimPrefix(req.URL.Path, "/v1/agent/service/maintenance/") -// entMeta := acl.NewEnterpriseMetaWithPartition(s.agent.config.PartitionOrDefault(), "") -// sid := structs.NewServiceID(serviceID, &entMeta) -// -// if sid.ID == "" { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing service ID"} -// } -// -// // Ensure we have some action -// params := req.URL.Query() -// if _, ok := params["enable"]; !ok { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing value for enable"} -// } -// -// raw := params.Get("enable") -// enable, err := strconv.ParseBool(raw) -// if err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid value for enable: %q", raw)} -// } -// -// // Get the provided token, if any, and vet against any ACL policies. -// var token string -// s.parseToken(req, &token) -// -// if err := s.parseEntMetaNoWildcard(req, &sid.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, &sid.EnterpriseMeta, nil) -// if err != nil { -// return nil, err -// } -// -// sid.Normalize() -// -// if !s.validateRequestPartition(resp, &sid.EnterpriseMeta) { -// return nil, nil -// } -// -// if err := s.agent.vetServiceUpdateWithAuthorizer(authz, sid); err != nil { -// return nil, err -// } -// -// if enable { -// reason := params.Get("reason") -// if err = s.agent.EnableServiceMaintenance(sid, reason, token); err != nil { -// return nil, HTTPError{StatusCode: http.StatusNotFound, Reason: err.Error()} -// } -// } else { -// if err = s.agent.DisableServiceMaintenance(sid); err != nil { -// return nil, HTTPError{StatusCode: http.StatusNotFound, Reason: err.Error()} -// } -// } -// s.syncChanges() -// return nil, nil -// } -// -// func (s *HTTPHandlers) AgentNodeMaintenance(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Ensure we have some action -// params := req.URL.Query() -// if _, ok := params["enable"]; !ok { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Missing value for enable"} -// } -// -// raw := params.Get("enable") -// enable, err := strconv.ParseBool(raw) -// if err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Invalid value for enable: %q", raw)} -// } -// -// // Get the provided token, if any, and vet against any ACL policies. -// var token string -// s.parseToken(req, &token) -// -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) -// if err != nil { -// return nil, err -// } -// -// var authzContext acl.AuthorizerContext -// s.agent.AgentEnterpriseMeta().FillAuthzContext(&authzContext) -// if err := authz.ToAllowAuthorizer().NodeWriteAllowed(s.agent.config.NodeName, &authzContext); err != nil { -// return nil, err -// } -// -// if enable { -// s.agent.EnableNodeMaintenance(params.Get("reason"), token) -// } else { -// s.agent.DisableNodeMaintenance() -// } -// s.syncChanges() -// return nil, nil -// } -// -// func (s *HTTPHandlers) AgentMonitor(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Fetch the ACL token, if any, and enforce agent policy. -// var token string -// s.parseToken(req, &token) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) -// if err != nil { -// return nil, err -// } -// -// // Authorize using the agent's own enterprise meta, not the token. -// var authzContext acl.AuthorizerContext -// s.agent.AgentEnterpriseMeta().FillAuthzContext(&authzContext) -// if err := authz.ToAllowAuthorizer().AgentReadAllowed(s.agent.config.NodeName, &authzContext); err != nil { -// return nil, err -// } -// -// // Get the provided loglevel. -// logLevel := req.URL.Query().Get("loglevel") -// if logLevel == "" { -// logLevel = "INFO" -// } -// -// var logJSON bool -// if _, ok := req.URL.Query()["logjson"]; ok { -// logJSON = true -// } -// -// if !logging.ValidateLogLevel(logLevel) { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Unknown log level: %s", logLevel)} -// } -// -// flusher, ok := resp.(http.Flusher) -// if !ok { -// return nil, fmt.Errorf("Streaming not supported") -// } -// -// monitor := monitor.New(monitor.Config{ -// BufferSize: 512, -// Logger: s.agent.logger, -// LoggerOptions: &hclog.LoggerOptions{ -// Level: logging.LevelFromString(logLevel), -// JSONFormat: logJSON, -// }, -// }) -// logsCh := monitor.Start() -// -// // Send header so client can start streaming body -// resp.WriteHeader(http.StatusOK) -// -// // 0 byte write is needed before the Flush call so that if we are using -// // a gzip stream it will go ahead and write out the HTTP response header -// resp.Write([]byte("")) -// flusher.Flush() -// const flushDelay = 200 * time.Millisecond -// flushTicker := time.NewTicker(flushDelay) -// defer flushTicker.Stop() -// -// // Stream logs until the connection is closed. -// for { -// select { -// case <-req.Context().Done(): -// droppedCount := monitor.Stop() -// if droppedCount > 0 { -// s.agent.logger.Warn("Dropped logs during monitor request", "dropped_count", droppedCount) -// } -// flusher.Flush() -// return nil, nil -// -// case log := <-logsCh: -// fmt.Fprint(resp, string(log)) -// -// case <-flushTicker.C: -// flusher.Flush() -// } -// } -// } -// -// func (s *HTTPHandlers) AgentToken(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// if s.checkACLDisabled() { -// return nil, HTTPError{StatusCode: http.StatusUnauthorized, Reason: "ACL support disabled"} -// } -// -// // Fetch the ACL token, if any, and enforce agent policy. -// var token string -// s.parseToken(req, &token) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) -// if err != nil { -// return nil, err -// } -// -// // Authorize using the agent's own enterprise meta, not the token. -// var authzContext acl.AuthorizerContext -// s.agent.AgentEnterpriseMeta().FillAuthzContext(&authzContext) -// if err := authz.ToAllowAuthorizer().AgentWriteAllowed(s.agent.config.NodeName, &authzContext); err != nil { -// return nil, err -// } -// -// // The body is just the token, but it's in a JSON object so we can add -// // fields to this later if needed. -// var args api.AgentToken -// if err := decodeBody(req.Body, &args); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Request decode failed: %v", err)} -// } -// -// // Figure out the target token. -// target := strings.TrimPrefix(req.URL.Path, "/v1/agent/token/") -// -// err = s.agent.tokens.WithPersistenceLock(func() error { -// triggerAntiEntropySync := false -// switch target { -// case "acl_token", "default": -// changed := s.agent.tokens.UpdateUserToken(args.Token, token_store.TokenSourceAPI) -// if changed { -// triggerAntiEntropySync = true -// } -// -// case "acl_agent_token", "agent": -// changed := s.agent.tokens.UpdateAgentToken(args.Token, token_store.TokenSourceAPI) -// if changed { -// triggerAntiEntropySync = true -// } -// -// case "acl_agent_master_token", "agent_master", "agent_recovery": -// s.agent.tokens.UpdateAgentRecoveryToken(args.Token, token_store.TokenSourceAPI) -// -// case "acl_replication_token", "replication": -// s.agent.tokens.UpdateReplicationToken(args.Token, token_store.TokenSourceAPI) -// -// case "config_file_service_registration": -// s.agent.tokens.UpdateConfigFileRegistrationToken(args.Token, token_store.TokenSourceAPI) -// -// default: -// return HTTPError{StatusCode: http.StatusNotFound, Reason: fmt.Sprintf("Token %q is unknown", target)} -// } -// -// // TODO: is it safe to move this out of WithPersistenceLock? -// if triggerAntiEntropySync { -// s.agent.sync.SyncFull.Trigger() -// } -// return nil -// }) -// if err != nil { -// return nil, err -// } -// -// s.agent.logger.Info("Updated agent's ACL token", "token", target) -// return nil, nil -// } -// -// // AgentConnectCARoots returns the trusted CA roots. -// func (s *HTTPHandlers) AgentConnectCARoots(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// var args structs.DCSpecificRequest -// if done := s.parse(resp, req, &args.Datacenter, &args.QueryOptions); done { -// return nil, nil -// } -// -// raw, m, err := s.agent.cache.Get(req.Context(), cachetype.ConnectCARootName, &args) -// if err != nil { -// return nil, err -// } -// defer setCacheMeta(resp, &m) -// -// // Add cache hit -// -// reply, ok := raw.(*structs.IndexedCARoots) -// if !ok { -// // This should never happen, but we want to protect against panics -// return nil, fmt.Errorf("internal error: response type not correct") -// } -// defer setMeta(resp, &reply.QueryMeta) -// -// return *reply, nil -// } -// -// // AgentConnectCALeafCert returns the certificate bundle for a service -// // instance. This endpoint ignores all "Cache-Control" attributes. -// // This supports blocking queries to update the returned bundle. -// // Non-blocking queries will always verify that the cache entry is still valid. -// func (s *HTTPHandlers) AgentConnectCALeafCert(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Get the service name. Note that this is the name of the service, -// // not the ID of the service instance. -// serviceName := strings.TrimPrefix(req.URL.Path, "/v1/agent/connect/ca/leaf/") -// -// // TODO(peering): expose way to get kind=mesh-gateway type cert with appropriate ACLs -// -// args := cachetype.ConnectCALeafRequest{ -// Service: serviceName, // Need name not ID -// } -// var qOpts structs.QueryOptions -// -// if err := s.parseEntMetaNoWildcard(req, &args.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// // Store DC in the ConnectCALeafRequest but query opts separately -// if done := s.parse(resp, req, &args.Datacenter, &qOpts); done { -// return nil, nil -// } -// args.MinQueryIndex = qOpts.MinQueryIndex -// args.MaxQueryTime = qOpts.MaxQueryTime -// args.Token = qOpts.Token -// -// // TODO(ffmmmm): maybe set MustRevalidate in ConnectCALeafRequest (as part of CacheInfo()) -// // We don't want non-blocking queries to return expired leaf certs -// // or leaf certs not valid under the current CA. So always revalidate -// // the leaf cert on non-blocking queries (ie when MinQueryIndex == 0) -// if args.MinQueryIndex == 0 { -// args.MustRevalidate = true -// } -// -// if !s.validateRequestPartition(resp, &args.EnterpriseMeta) { -// return nil, nil -// } -// -// raw, m, err := s.agent.cache.Get(req.Context(), cachetype.ConnectCALeafName, &args) -// if err != nil { -// return nil, err -// } -// defer setCacheMeta(resp, &m) -// -// reply, ok := raw.(*structs.IssuedCert) -// if !ok { -// // This should never happen, but we want to protect against panics -// return nil, fmt.Errorf("internal error: response type not correct") -// } -// setIndex(resp, reply.ModifyIndex) -// -// return reply, nil -// } -// -// // AgentConnectAuthorize -// // -// // POST /v1/agent/connect/authorize -// // -// // NOTE: This endpoint treats any L7 intentions as DENY. -// // -// // Note: when this logic changes, consider if the Intention.Check RPC method -// // also needs to be updated. -// func (s *HTTPHandlers) AgentConnectAuthorize(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Fetch the token -// var token string -// s.parseToken(req, &token) -// -// var authReq structs.ConnectAuthorizeRequest -// -// if err := s.parseEntMetaNoWildcard(req, &authReq.EnterpriseMeta); err != nil { -// return nil, err -// } -// -// if err := decodeBody(req.Body, &authReq); err != nil { -// return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Request decode failed: %v", err)} -// } -// -// if !s.validateRequestPartition(resp, &authReq.EnterpriseMeta) { -// return nil, nil -// } -// -// authz, reason, cacheMeta, err := s.agent.ConnectAuthorize(token, &authReq) -// if err != nil { -// return nil, err -// } -// setCacheMeta(resp, cacheMeta) -// -// return &connectAuthorizeResp{ -// Authorized: authz, -// Reason: reason, -// }, nil -// } -// -// // connectAuthorizeResp is the response format/structure for the -// // /v1/agent/connect/authorize endpoint. -// type connectAuthorizeResp struct { -// Authorized bool // True if authorized, false if not -// Reason string // Reason for the Authorized value (whether true or false) -// } -// -// // AgentHost -// // -// // GET /v1/agent/host -// // -// // Retrieves information about resources available and in-use for the -// // host the agent is running on such as CPU, memory, and disk usage. Requires -// // a operator:read ACL token. -// func (s *HTTPHandlers) AgentHost(resp http.ResponseWriter, req *http.Request) (interface{}, error) { -// // Fetch the ACL token, if any, and enforce agent policy. -// var token string -// s.parseToken(req, &token) -// authz, err := s.agent.delegate.ResolveTokenAndDefaultMeta(token, nil, nil) -// if err != nil { -// return nil, err -// } -// -// // TODO(partitions): should this be possible in a partition? -// if err := authz.ToAllowAuthorizer().OperatorReadAllowed(nil); err != nil { -// return nil, err -// } -// -// return debug.CollectHostInfo(), nil -// }
M agent/config.goagent/config.go

@@ -17,7 +17,6 @@ if err != nil {

panic(err) } - // TODO: figure out how to default the listeners cfg := Config{} cfg.DNSBindAddr = &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: DefaultDNSPort} cfg.HTTPBindAddr = &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: DefaultHTTPPort}

@@ -41,5 +40,5 @@ HTTPResponseHeaders map[string]string

} func (c *Config) VersionWithMetadata() string { - return "todo" + return "TODO" }
M command/ls/ls.gocommand/ls/ls.go

@@ -17,8 +17,12 @@ if len(args) == 0 {

fmt.Printf(usage) os.Exit(1) } - switch args[0] { + subcommand := args[0] + switch subcommand { case "members": members.Run(args[1:]) + default: + fmt.Fprintf(os.Stderr, "'%s' is not a valid subcommand\n\n%s", subcommand, usage) + os.Exit(1) } }
M command/ls/members/members.gocommand/ls/members/members.go

@@ -1,9 +1,11 @@

package members import ( + "bytes" "flag" "fmt" "os" + "text/tabwriter" "git.j3s.sh/cascade/api" )

@@ -44,11 +46,26 @@ fmt.Println(err)

os.Exit(1) } members, err := client.Agent().Members() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + var b bytes.Buffer + tw := tabwriter.NewWriter(&b, 0, 2, 2, ' ', 0) + if membersFlags.details { + fmt.Fprintf(tw, "node\taddr\tstatus\n") + } for _, m := range members { if membersFlags.details { - fmt.Printf("%s %s:%d %s\n", m.Name, m.Addr, m.Port, m.StatusPretty()) + fmt.Fprintf(tw, "%s\t%s:%d\t%s\n", m.Name, m.Addr, m.Port, m.StatusPretty()) } else { - fmt.Println(m.Name) + fmt.Fprintf(tw, "%s\n", m.Name) } } + if err := tw.Flush(); err != nil { + fmt.Printf("error flushing tabwriter: %s", err) + os.Exit(1) + } + fmt.Print(b.String()) }