package dockerswarm import ( "encoding/json" "fmt" "net/url" "strings" "github.com/VictoriaMetrics/VictoriaMetrics/lib/logger" "github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils" ) var configMap = discoveryutils.NewConfigMap() type apiConfig struct { client *discoveryutils.Client port int // role is the type of objects to discover. // // filtersQueryArg is applied only to the given role - the rest of objects are queried without filters. role string // filtersQueryArg contains escaped `filters` query arg to add to each request to Docker Swarm API. filtersQueryArg string } func getAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) { v, err := configMap.Get(sdc, func() (interface{}, error) { return newAPIConfig(sdc, baseDir) }) if err != nil { return nil, err } return v.(*apiConfig), nil } func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) { cfg := &apiConfig{ port: sdc.Port, filtersQueryArg: getFiltersQueryArg(sdc.Filters), } if cfg.port == 0 { cfg.port = 80 } ac, err := sdc.HTTPClientConfig.NewConfig(baseDir) if err != nil { return nil, fmt.Errorf("cannot parse auth config: %w", err) } proxyAC, err := sdc.ProxyClientConfig.NewConfig(baseDir) if err != nil { return nil, fmt.Errorf("cannot parse proxy auth config: %w", err) } client, err := discoveryutils.NewClient(sdc.Host, ac, sdc.ProxyURL, proxyAC, sdc.HTTPClientConfig.FollowRedirects) if err != nil { return nil, fmt.Errorf("cannot create HTTP client for %q: %w", sdc.Host, err) } cfg.client = client cfg.role = sdc.Role return cfg, nil } func (cfg *apiConfig) getAPIResponse(path, filtersQueryArg string) ([]byte, error) { if len(filtersQueryArg) > 0 { separator := "?" if strings.Contains(path, "?") { separator = "&" } path += separator + "filters=" + cfg.filtersQueryArg } return cfg.client.GetAPIResponse(path) } // Encodes filters as `map[string][]string` and then marshals it to JSON. // Reference: https://docs.docker.com/engine/api/v1.41/#tag/Task func getFiltersQueryArg(filters []Filter) string { if len(filters) == 0 { return "" } m := make(map[string][]string) for _, f := range filters { m[f.Name] = f.Values } buf, err := json.Marshal(m) if err != nil { logger.Panicf("BUG: unexpected error in json.Marshal: %s", err) } return url.QueryEscape(string(buf)) }