Skip to content

Commit

Permalink
add kubeutil python module to support kubelet check (#1146)
Browse files Browse the repository at this point in the history
  • Loading branch information
xvello authored Feb 5, 2018
1 parent 95e948d commit d85eae5
Show file tree
Hide file tree
Showing 19 changed files with 374 additions and 34 deletions.
5 changes: 5 additions & 0 deletions pkg/collector/py/api.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython

#include "api.h"
Expand Down
5 changes: 5 additions & 0 deletions pkg/collector/py/api.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython

#ifndef _PY_API_H
Expand Down
5 changes: 5 additions & 0 deletions pkg/collector/py/datadog_agent.c
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython

#include "datadog_agent.h"
Expand Down
5 changes: 5 additions & 0 deletions pkg/collector/py/datadog_agent.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython

#ifndef DATADOG_HEADER
Expand Down
26 changes: 26 additions & 0 deletions pkg/collector/py/kubeutil.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython,kubelet

#include "kubeutil.h"

// Functions
PyObject* GetKubeletConnectionInfo();

static PyMethodDef kubeutilMethods[] = {
{"get_connection_info", GetKubeletConnectionInfo, METH_NOARGS, "Get kubelet connection information."},
{NULL, NULL}
};

void initkubeutil()
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();

PyObject *ku = Py_InitModule("kubeutil", kubeutilMethods);

PyGILState_Release(gstate);
}
74 changes: 74 additions & 0 deletions pkg/collector/py/kubeutil.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython,kubelet

package py

import (
"time"
"unsafe"

log "github.com/cihub/seelog"

"github.com/DataDog/datadog-agent/pkg/util/cache"
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/kubelet"
)

// #cgo pkg-config: python-2.7
// #cgo linux CFLAGS: -std=gnu99
// #include "api.h"
// #include "kubeutil.h"
import "C"

var kubeletCacheKey = cache.BuildAgentKey("py", "kubeutil", "connection_info")

// GetKubeletConnectionInfo returns a dict containing url and credentials to connect to the kubelet.
// The dict is empty if the kubelet was not detected. The call to kubeutil is cached for 5 minutes.
// See the documentation of kubelet.GetRawConnectionInfo for dict contents.
//export GetKubeletConnectionInfo
func GetKubeletConnectionInfo() *C.PyObject {
var creds map[string]string
var ok bool
dict := C.PyDict_New()

if cached, hit := cache.Cache.Get(kubeletCacheKey); hit {
creds, ok = cached.(map[string]string)
if !ok {
log.Errorf("invalid cache format, forcing a cache miss")
creds = nil
}
}

if creds == nil { // Cache miss
kubeutil, err := kubelet.GetKubeUtil()
if err != nil {
// Connection to the kubelet fail, return empty dict
return dict
}
// At this point, we have valid credentials to get
creds = kubeutil.GetRawConnectionInfo()
cache.Cache.Set(kubeletCacheKey, creds, 5*time.Minute)
}

for k, v := range creds {
cKey := C.CString(k)
pyKey := C.PyString_FromString(cKey)
defer C.Py_DecRef(pyKey)
C.free(unsafe.Pointer(cKey))

cVal := C.CString(v)
pyVal := C.PyString_FromString(cVal)
defer C.Py_DecRef(pyVal)
C.free(unsafe.Pointer(cVal))

C.PyDict_SetItem(dict, pyKey, pyVal)
}
return dict
}

func initkubeutil() {
C.initkubeutil()
}
15 changes: 15 additions & 0 deletions pkg/collector/py/kubeutil.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython,kubelet

#ifndef KUBEUTIL_HEADER
#define KUBEUTIL_HEADER

#include <Python.h>

void initkubeutil();

#endif /* KUBEUTIL_HEADER */
12 changes: 12 additions & 0 deletions pkg/collector/py/kubeutil_nokubelet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython,!kubelet

package py

// Stub
func initkubeutil() {
}
51 changes: 51 additions & 0 deletions pkg/collector/py/kubeutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2018 Datadog, Inc.

// +build cpython,kubelet

// NOTICE: See TestMain function in `utils_test.go` for Python initialization
package py

import (
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/DataDog/datadog-agent/pkg/config"
"github.com/DataDog/datadog-agent/pkg/util/cache"
"github.com/DataDog/datadog-agent/pkg/util/kubernetes/kubelet"
)

func TestGetKubeletConnectionInfoNotFound(t *testing.T) {
config.Datadog.Set("kubernetes_http_kubelet_port", 0)
config.Datadog.Set("kubernetes_https_kubelet_port", 0)
kubelet.ResetGlobalKubeUtil()
cache.Cache.Delete(kubeletCacheKey)

check, _ := getCheckInstance("testkubeutil", "TestCheck")
err := check.Run()
assert.Nil(t, err)

warnings := check.GetWarnings()
require.Len(t, warnings, 1)
assert.Equal(t, "Kubelet not found", warnings[0].Error())
}

func TestGetKubeletConnectionInfoFromCache(t *testing.T) {
dummyCreds := map[string]string{
"url": "https://10.0.0.1:10250",
}
cache.Cache.Set(kubeletCacheKey, dummyCreds, 5*time.Minute)

check, _ := getCheckInstance("testkubeutil", "TestCheck")
err := check.Run()
assert.Nil(t, err)

warnings := check.GetWarnings()
require.Len(t, warnings, 1)
assert.Equal(t, "Found kubelet at https://10.0.0.1:10250", warnings[0].Error())
}
2 changes: 1 addition & 1 deletion pkg/collector/py/py.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func Initialize(paths ...string) *python.PyThreadState {
// (all these calls will take care of the GIL)
initAPI() // `aggregator` module
initDatadogAgent() // `datadog_agent` module

initkubeutil() // `kubeutil` module if compiled in
// return the state so the caller can resume
return state
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/collector/py/tests/testkubeutil.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Unless explicitly stated otherwise all files in this repository are licensed
# under the Apache License Version 2.0.
# This product includes software developed at Datadog (https://www.datadoghq.com/).
# Copyright 2018 Datadog, Inc.

from checks import AgentCheck
from kubeutil import get_connection_info


class TestCheck(AgentCheck):
def check(self, instance):
creds = get_connection_info()
if creds.get("url"):
self.warning("Found kubelet at " + creds.get("url"))
else:
self.warning("Kubelet not found")
2 changes: 1 addition & 1 deletion pkg/util/kubernetes/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func GetBearerToken(authTokenPath string) (string, error) {
if err != nil {
return "", fmt.Errorf("could not read token from %s: %s", authTokenPath, err)
}
return fmt.Sprintf("bearer %s", token), nil
return string(token), nil
}

// GetCertificates loads the certificate and the private key
Expand Down
9 changes: 4 additions & 5 deletions pkg/util/kubernetes/kubelet/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,19 @@ func isConfiguredTLSVerify() bool {
return config.Datadog.GetBool("kubelet_tls_verify")
}

func getTLSConfig() (*tls.Config, error) {
func buildTLSConfig(verifyTLS bool, caPath string) (*tls.Config, error) {
tlsConfig := &tls.Config{}
if isConfiguredTLSVerify() == false {
if verifyTLS == false {
tlsConfig.InsecureSkipVerify = true
return tlsConfig, nil
}

certPath := config.Datadog.GetString("kubelet_client_ca")
if certPath == "" {
if caPath == "" {
log.Debugf("kubelet_client_ca isn't configured: certificate authority must be trusted")
return nil, nil
}

caPool, err := kubernetes.GetCertificateAuthority(certPath)
caPool, err := kubernetes.GetCertificateAuthority(caPath)
if err != nil {
return tlsConfig, err
}
Expand Down
Loading

0 comments on commit d85eae5

Please sign in to comment.