internal/kibana/send_config.go (78 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package kibana
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/elastic/elastic-agent-libs/mapstr"
"github.com/elastic/go-ucfg"
)
const kibanaConfigUploadPath = "/api/apm/fleet/apm_server_schema"
// SendConfig marshals and uploads the provided config to kibana using the
// provided ConnectingClient. It retries until its context has been canceled or
// the upload succeeds.
func SendConfig(ctx context.Context, client *Client, conf *ucfg.Config) error {
// configuration options are already flattened (dotted)
// any credentials for ES and Kibana are removed
flat, err := flattenAndClean(conf)
if err != nil {
return err
}
b, err := json.Marshal(format(flat))
if err != nil {
return err
}
resp, err := client.Send(ctx, http.MethodPost, kibanaConfigUploadPath, nil, nil, bytes.NewReader(b))
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode > http.StatusOK {
return fmt.Errorf("bad response %s", resp.Status)
}
return nil
}
func format(m map[string]interface{}) map[string]interface{} {
return map[string]interface{}{"schema": m}
}
func flattenAndClean(conf *ucfg.Config) (map[string]interface{}, error) {
m := mapstr.M{}
if err := conf.Unpack(m); err != nil {
return nil, err
}
flat := m.Flatten()
out := make(mapstr.M, len(flat))
for k, v := range flat {
// remove if elasticsearch is NOT in the front position?
// *.elasticsearch.* according to axw
if strings.Contains(k, "elasticsearch") {
continue
}
if strings.Contains(k, "kibana") {
continue
}
if strings.HasPrefix(k, "instrumentation") {
continue
}
if strings.HasPrefix(k, "logging.") {
switch k[8:] {
case "level", "selectors", "metrics.enabled", "metrics.period":
default:
continue
}
}
if strings.HasPrefix(k, "path") {
continue
}
if k == "gc_percent" || k == "name" || k == "xpack.monitoring.enabled" {
continue
}
if k == "apm-server.host" {
v = "0.0.0.0:8200"
}
if strings.HasPrefix(k, "apm-server.ssl.") {
// Following ssl related settings need to be synced:
// apm-server.ssl.enabled
// apm-server.ssl.certificate
// apm-server.ssl.key
switch k[15:] {
case "enabled", "certificate", "key":
default:
continue
}
}
out[k] = v
}
return out, nil
}