Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added auto detection for kubelet client config #19

Merged
merged 6 commits into from
Nov 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ GOPATH := $(shell go env GOPATH)
GORELEASER_VERSION := v0.129.0
GORELEASER_SHA256 := e9e61de6565ad4acbe33a944abbeaf0d75582c10b89b793c99acd41a0846c166
GORELEASER_BIN ?= bin/goreleaser
GOLANGCILINT_VERSION = v1.24.0
GOLANGCILINT_VERSION = v1.27.0
GOLANGCI_LINT_BIN = bin/golangci-lint

all: build
Expand Down
4 changes: 3 additions & 1 deletion cmd/discovery/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"log"
"os"
"time"

cfg "github.com/newrelic/nri-discovery-kubernetes/internal/config"
"github.com/newrelic/nri-discovery-kubernetes/internal/discovery"
Expand All @@ -20,7 +21,8 @@ func main() {

config := cfg.NewConfig(Version)

kubelet, err := kubernetes.NewKubelet(config.Port, config.TLS)
timeout := time.Duration(config.Timeout) * time.Millisecond
kubelet, err := kubernetes.NewKubelet(config.Host, config.Port, config.TLS, config.IsAutoConfig(), timeout)
if err != nil {
log.Printf("failed to get Kubernetes configuration: %s", err)
os.Exit(1)
Expand Down
27 changes: 24 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,40 @@ module github.com/newrelic/nri-discovery-kubernetes
go 1.13

require (
cloud.google.com/go v0.38.0 // indirect
github.com/Azure/go-autorest/autorest v0.9.0 // indirect
github.com/evanphx/json-patch v4.2.0+incompatible // indirect
github.com/gogo/protobuf v1.3.1 // indirect
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.3.0 // indirect
github.com/google/uuid v1.1.1 // indirect
github.com/gophercloud/gophercloud v0.1.0 // indirect
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7 // indirect
github.com/hashicorp/golang-lru v0.5.1 // indirect
github.com/imdario/mergo v0.3.8 // indirect
github.com/json-iterator/go v1.1.8 // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/newrelic/nri-kubernetes v1.26.5
github.com/onsi/ginkgo v1.10.1 // indirect
github.com/onsi/gomega v1.7.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/sirupsen/logrus v1.2.0
github.com/spf13/pflag v1.0.5
github.com/spf13/viper v1.6.2
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20191112222119-e1110fd1c708 // indirect
golang.org/x/net v0.0.0-20191112182307-2180aed22343 // indirect
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 // indirect
golang.org/x/sys v0.0.0-20191113165036-4c7a9d0fe056 // indirect
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
google.golang.org/appengine v1.6.5 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.2.5 // indirect
k8s.io/api v0.0.0-20191115095533-47f6de673b26
k8s.io/apimachinery v0.0.0-20191115015347-3c7067801da2
k8s.io/client-go v0.0.0-20191114101535-6c5935290e33
k8s.io/api v0.0.0-20180521142803-feb48db456a5
k8s.io/apimachinery v0.0.0-20180515182440-31dade610c05
k8s.io/client-go v7.0.0+incompatible
k8s.io/klog v1.0.0 // indirect
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a // indirect
k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6 // indirect
)
49 changes: 49 additions & 0 deletions go.sum

Large diffs are not rendered by default.

31 changes: 30 additions & 1 deletion internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,31 @@ import (
const (
namespaces = "namespaces"
port = "port"
Host = "host"
insecure = "insecure"
timeout = "timeout"
tls = "tls"
envPrefix = "NRIA"

DefaultHost = "localhost"
DefaultPort = 10255
)

var _ = flag.String(namespaces, "", "(optional, default '') Comma separated list of namespaces to discover pods on")
var _ = flag.Bool(insecure, false, `(optional, default false, deprecated) Use insecure (non-ssl) connection.
For backwards compatibility this flag takes precedence over 'tls')`)
var _ = flag.Int(timeout, 5000, "(optional, default 5000) timeout in ms")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need to mention this new flag in PR description + release notes?

var _ = flag.Bool(tls, false, "(optional, default false) Use secure (tls) connection")
var _ = flag.Int(port, 10255, "(optional, default 10255) Port used to connect to the kubelet")
var _ = flag.Int(port, DefaultPort, "(optional, default 10255) Port used to connect to the kubelet")
var _ = flag.String(Host, DefaultHost, "(optional, default "+DefaultHost+") Host used to connect to the kubelet")

// Config defined the currently accepted configuration parameters of the Discoverer
type Config struct {
Namespaces []string
Port int
Host string
TLS bool
Timeout int
}

func splitStrings(str string) []string {
Expand All @@ -35,14 +44,32 @@ func splitStrings(str string) []string {
return []string{}
}

// IsFlagPassed checks if a particular command line argument was provided or not.
func IsFlagPassed(name string) bool {
found := false
flag.Visit(func(f *flag.Flag) {
if f.Name == name {
found = true
}
})
return found
}

// IsAutoConfig returns true if no config parameter was provided as cmd line arg.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool 👍

func (c *Config) IsAutoConfig() bool {
return !IsFlagPassed(Host) && !IsFlagPassed(port) && !IsFlagPassed(tls)
}

func NewConfig(version string) Config {
flag.Parse()

v := viper.New()
_ = v.BindPFlag(namespaces, flag.Lookup(namespaces))
_ = v.BindPFlag(port, flag.Lookup(port))
_ = v.BindPFlag(Host, flag.Lookup(Host))
_ = v.BindPFlag(tls, flag.Lookup(tls))
_ = v.BindPFlag(insecure, flag.Lookup(insecure))
_ = v.BindPFlag(timeout, flag.Lookup(timeout))

v.SetEnvPrefix(envPrefix)
v.AutomaticEnv()
Expand All @@ -56,6 +83,8 @@ func NewConfig(version string) Config {
return Config{
Namespaces: splitStrings(v.GetString(namespaces)),
Port: v.GetInt(port),
Host: v.GetString(Host),
TLS: useTLS,
Timeout: v.GetInt(timeout),
}
}
48 changes: 46 additions & 2 deletions internal/http/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ package http
import (
"crypto/tls"
"errors"
nriK8sClient "github.com/newrelic/nri-kubernetes/src/client"
nriKubeletClient "github.com/newrelic/nri-kubernetes/src/kubelet/client"
"github.com/sirupsen/logrus"
"io/ioutil"
"net/http"
netHttp "net/http"
"net/url"
"os"
"time"
)

type HttpClient interface {
Expand All @@ -26,12 +32,13 @@ func (c *httpClient) Get(path string) ([]byte, error) {
return nil, err
}

defer resp.Body.Close()
buff, _ := ioutil.ReadAll(resp.Body)

if resp.StatusCode != http.StatusOK {
return nil, errors.New(resp.Status)
}

buff, _ := ioutil.ReadAll(resp.Body)
_ = resp.Body.Close()
return buff, nil
}

Expand All @@ -47,3 +54,40 @@ func NewClient(url url.URL, token string) HttpClient {
token: token,
}
}

// kubeletClient addapts the nri-kubernetes kubelet client.
type kubeletClient struct {
client nriK8sClient.HTTPClient
}

// NewKubeletClient creates a new kubeletClient instance.
func NewKubeletClient(nodeName string, timeout time.Duration) (HttpClient, error) {
logger := logrus.New()
logger.SetOutput(os.Stderr)
d, err := nriKubeletClient.NewDiscoverer(nodeName, logger)
if err != nil {
return nil, err
}
client, err := d.Discover(timeout)
if err != nil {
return nil, err
}
return &kubeletClient{
client: client,
}, nil
}

func (kc *kubeletClient) Get(path string) ([]byte, error) {
resp, err := kc.client.Do(netHttp.MethodGet, path)
if err != nil {
return nil, err
}

defer resp.Body.Close()
buff, _ := ioutil.ReadAll(resp.Body)

if resp.StatusCode != netHttp.StatusOK {
carlosroman marked this conversation as resolved.
Show resolved Hide resolved
return nil, errors.New(resp.Status)
carlosroman marked this conversation as resolved.
Show resolved Hide resolved
}
return buff, nil
}
41 changes: 28 additions & 13 deletions internal/kubernetes/kubelet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ package kubernetes
import (
"encoding/json"
"fmt"
"net/url"
"os"
"path/filepath"
"strconv"

configPkg "github.com/newrelic/nri-discovery-kubernetes/internal/config"
"github.com/newrelic/nri-discovery-kubernetes/internal/http"
"github.com/newrelic/nri-discovery-kubernetes/internal/utils"
"github.com/sirupsen/logrus"
v1 "k8s.io/api/core/v1"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"net/url"
"os"
"path/filepath"
"strconv"
"time"
)

const host = "localhost"
const podsPath = "/pods"
const clusterNameEnvVar = "CLUSTER_NAME"
const kubeletHostEnvVar = "NRK8S_NODE_NAME"
const nodeNameEnvVar = "NRK8S_NODE_NAME"

type PortsMap map[string]int32
type LabelsMap map[string]string
Expand Down Expand Up @@ -147,7 +148,7 @@ func getClusterName() string {
return clusterName
}

func NewKubelet(port int, useTLS bool) (Kubelet, error) {
func NewKubelet(host string, port int, useTLS bool, autoConfig bool, timeout time.Duration) (Kubelet, error) {
config, err := rest.InClusterConfig()
// not inside the cluster?
if err != nil {
Expand All @@ -159,12 +160,26 @@ func NewKubelet(port int, useTLS bool) (Kubelet, error) {
}

clusterName := getClusterName()
kubeletHost, isKubeletHostSet := os.LookupEnv(kubeletHostEnvVar)
nodeName, isNodeNameSet := os.LookupEnv(nodeNameEnvVar)
if autoConfig && isNodeNameSet {
client, err := http.NewKubeletClient(nodeName, timeout)
if err != nil {
logrus.WithError(err).Warn("failed to initialize kubelet client")
} else {
kubelet := &kubelet{
client: &client,
NodeName: nodeName,
ClusterName: clusterName,
}
return kubelet, nil
}
}

if !isKubeletHostSet {
// If the environment variable represented by kubeletHostEnvVar is not set,
// fallback to the default value.
kubeletHost = host
// host provided by cmd line arg has higher precedence.
// if host cmd line arg is not provided use NRK8S_NODE_NAME in case is set, otherwise localhost.
var kubeletHost = host
if isNodeNameSet && !configPkg.IsFlagPassed(configPkg.Host) {
kubeletHost = nodeName
}

hostUrl := makeUrl(kubeletHost, port, useTLS)
Expand Down
5 changes: 0 additions & 5 deletions internal/kubernetes/kubelet_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ import (
"testing"
)

func pointerToBool(b bool) *bool {
return &b
}

func getPod(phase v1.PodPhase, containerStatus ...v1.ContainerStatus) v1.Pod {
return v1.Pod{
Status: v1.PodStatus{
Expand All @@ -29,7 +25,6 @@ func buildContainerStatus(containerName string, containerState v1.ContainerState
Image: "k8s.gcr.io/kube-scheduler:v1.18.2",
ImageID: "docker-pullable://k8s.gcr.io/kube-scheduler@sha256:69f90a33b64c99e4c78e3cae36b0c767729b5a54203aa35524b1033708d1b482",
ContainerID: "docker://fd5fd1918be39db9992067f87f4daa755c83adbec63aece69879fb29d45514a0",
Started: pointerToBool(true),
}
}

Expand Down