summaryrefslogtreecommitdiffstats
path: root/src/go/collectors/go.d.plugin/modules/vcsa
diff options
context:
space:
mode:
authorIlya Mashchenko <ilya@netdata.cloud>2024-03-05 16:40:19 +0200
committerGitHub <noreply@github.com>2024-03-05 16:40:19 +0200
commit4c1adba5073294537f7233634ad15684018a42cf (patch)
treef2fc7526e8cc585187e4006c4126f42c0f54b3a1 /src/go/collectors/go.d.plugin/modules/vcsa
parentd8827d1e5ff927623d16b2e67ad9123e5f5b24ea (diff)
go.d.plugin dyncfgv2 (#17064)
Diffstat (limited to 'src/go/collectors/go.d.plugin/modules/vcsa')
-rw-r--r--src/go/collectors/go.d.plugin/modules/vcsa/config_schema.json191
-rw-r--r--src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.json20
-rw-r--r--src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.yaml17
-rw-r--r--src/go/collectors/go.d.plugin/modules/vcsa/vcsa.go45
-rw-r--r--src/go/collectors/go.d.plugin/modules/vcsa/vcsa_test.go102
5 files changed, 271 insertions, 104 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/vcsa/config_schema.json b/src/go/collectors/go.d.plugin/modules/vcsa/config_schema.json
index aab0647abc..f37b92076a 100644
--- a/src/go/collectors/go.d.plugin/modules/vcsa/config_schema.json
+++ b/src/go/collectors/go.d.plugin/modules/vcsa/config_schema.json
@@ -1,59 +1,158 @@
{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "go.d/vcsa job configuration schema.",
- "type": "object",
- "properties": {
- "name": {
- "type": "string"
+ "jsonSchema": {
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "title": "vCenter Server Appliance collector configuration.",
+ "type": "object",
+ "properties": {
+ "update_every": {
+ "title": "Update every",
+ "description": "Data collection interval, measured in seconds.",
+ "type": "integer",
+ "minimum": 1,
+ "default": 1
+ },
+ "url": {
+ "title": "URL",
+ "description": "The base URL of the VCSA server.",
+ "type": "string",
+ "format": "uri"
+ },
+ "timeout": {
+ "title": "Timeout",
+ "description": "The timeout in seconds for the HTTP request.",
+ "type": "number",
+ "minimum": 0.5,
+ "default": 1
+ },
+ "not_follow_redirects": {
+ "title": "Not follow redirects",
+ "description": "If set, the client will not follow HTTP redirects automatically.",
+ "type": "boolean"
+ },
+ "username": {
+ "title": "Username",
+ "description": "The username for basic authentication.",
+ "type": "string",
+ "sensitive": true
+ },
+ "password": {
+ "title": "Password",
+ "description": "The password for basic authentication.",
+ "type": "string",
+ "sensitive": true
+ },
+ "proxy_url": {
+ "title": "Proxy URL",
+ "description": "The URL of the proxy server.",
+ "type": "string"
+ },
+ "proxy_username": {
+ "title": "Proxy username",
+ "description": "The username for proxy authentication.",
+ "type": "string",
+ "sensitive": true
+ },
+ "proxy_password": {
+ "title": "Proxy password",
+ "description": "The password for proxy authentication.",
+ "type": "string",
+ "sensitive": true
+ },
+ "headers": {
+ "title": "Headers",
+ "description": "Additional HTTP headers to include in the request.",
+ "type": "object",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "tls_skip_verify": {
+ "title": "Skip TLS verification",
+ "description": "If set, TLS certificate verification will be skipped.",
+ "type": "boolean"
+ },
+ "tls_ca": {
+ "title": "TLS CA",
+ "description": "The path to the CA certificate file for TLS verification.",
+ "type": "string"
+ },
+ "tls_cert": {
+ "title": "TLS certificate",
+ "description": "The path to the client certificate file for TLS authentication.",
+ "type": "string"
+ },
+ "tls_key": {
+ "title": "TLS key",
+ "description": "The path to the client key file for TLS authentication.",
+ "type": "string"
+ }
+ },
+ "required": [
+ "url"
+ ]
+ },
+ "uiSchema": {
+ "ui:flavour": "tabs",
+ "ui:options": {
+ "tabs": [
+ {
+ "title": "Base",
+ "fields": [
+ "update_every",
+ "url",
+ "timeout",
+ "not_follow_redirects"
+ ]
+ },
+ {
+ "title": "Auth",
+ "fields": [
+ "username",
+ "password"
+ ]
+ },
+ {
+ "title": "TLS",
+ "fields": [
+ "tls_skip_verify",
+ "tls_ca",
+ "tls_cert",
+ "tls_key"
+ ]
+ },
+ {
+ "title": "Proxy",
+ "fields": [
+ "proxy_url",
+ "proxy_username",
+ "proxy_password"
+ ]
+ },
+ {
+ "title": "Headers",
+ "fields": [
+ "headers"
+ ]
+ }
+ ]
+ },
+ "uiOptions": {
+ "fullPage": true
},
"url": {
- "type": "string"
+ "ui:placeholder": "https://203.0.113.0"
},
"timeout": {
- "type": [
- "string",
- "integer"
- ]
+ "ui:help": "Accepts decimals for precise control (e.g., type 1.5 for 1.5 seconds)."
},
"username": {
- "type": "string"
+ "ui:placeholder": "admin@vsphere.local"
},
"password": {
- "type": "string"
- },
- "proxy_url": {
- "type": "string"
- },
- "proxy_username": {
- "type": "string"
+ "ui:widget": "password"
},
"proxy_password": {
- "type": "string"
- },
- "headers": {
- "type": "object",
- "additionalProperties": {
- "type": "string"
- }
- },
- "not_follow_redirects": {
- "type": "boolean"
- },
- "tls_ca": {
- "type": "string"
- },
- "tls_cert": {
- "type": "string"
- },
- "tls_key": {
- "type": "string"
- },
- "insecure_skip_verify": {
- "type": "boolean"
+ "ui:widget": "password"
}
- },
- "required": [
- "name",
- "url"
- ]
+ }
}
diff --git a/src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.json b/src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.json
new file mode 100644
index 0000000000..984c3ed6e7
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.json
@@ -0,0 +1,20 @@
+{
+ "update_every": 123,
+ "url": "ok",
+ "body": "ok",
+ "method": "ok",
+ "headers": {
+ "ok": "ok"
+ },
+ "username": "ok",
+ "password": "ok",
+ "proxy_url": "ok",
+ "proxy_username": "ok",
+ "proxy_password": "ok",
+ "timeout": 123.123,
+ "not_follow_redirects": true,
+ "tls_ca": "ok",
+ "tls_cert": "ok",
+ "tls_key": "ok",
+ "tls_skip_verify": true
+}
diff --git a/src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.yaml
new file mode 100644
index 0000000000..8558b61cc0
--- /dev/null
+++ b/src/go/collectors/go.d.plugin/modules/vcsa/testdata/config.yaml
@@ -0,0 +1,17 @@
+update_every: 123
+url: "ok"
+body: "ok"
+method: "ok"
+headers:
+ ok: "ok"
+username: "ok"
+password: "ok"
+proxy_url: "ok"
+proxy_username: "ok"
+proxy_password: "ok"
+timeout: 123.123
+not_follow_redirects: yes
+tls_ca: "ok"
+tls_cert: "ok"
+tls_key: "ok"
+tls_skip_verify: yes
diff --git a/src/go/collectors/go.d.plugin/modules/vcsa/vcsa.go b/src/go/collectors/go.d.plugin/modules/vcsa/vcsa.go
index 1b319fe85a..f5e86d082d 100644
--- a/src/go/collectors/go.d.plugin/modules/vcsa/vcsa.go
+++ b/src/go/collectors/go.d.plugin/modules/vcsa/vcsa.go
@@ -4,11 +4,11 @@ package vcsa
import (
_ "embed"
+ "errors"
"time"
- "github.com/netdata/netdata/go/go.d.plugin/pkg/web"
-
"github.com/netdata/netdata/go/go.d.plugin/agent/module"
+ "github.com/netdata/netdata/go/go.d.plugin/pkg/web"
)
//go:embed "config_schema.json"
@@ -29,7 +29,7 @@ func New() *VCSA {
Config: Config{
HTTP: web.HTTP{
Client: web.Client{
- Timeout: web.Duration{Duration: time.Second * 5},
+ Timeout: web.Duration(time.Second * 5),
},
},
},
@@ -38,17 +38,18 @@ func New() *VCSA {
}
type Config struct {
- web.HTTP `yaml:",inline"`
+ web.HTTP `yaml:",inline" json:""`
+ UpdateEvery int `yaml:"update_every" json:"update_every"`
}
type (
VCSA struct {
module.Base
- Config `yaml:",inline"`
-
- client healthClient
+ Config `yaml:",inline" json:""`
charts *module.Charts
+
+ client healthClient
}
healthClient interface {
@@ -66,33 +67,47 @@ type (
}
)
-func (vc *VCSA) Init() bool {
+func (vc *VCSA) Configuration() any {
+ return vc.Config
+}
+
+func (vc *VCSA) Init() error {
if err := vc.validateConfig(); err != nil {
vc.Error(err)
- return false
+ return err
}
c, err := vc.initHealthClient()
if err != nil {
vc.Errorf("error on creating health client : %vc", err)
- return false
+ return err
}
vc.client = c
vc.Debugf("using URL %s", vc.URL)
- vc.Debugf("using timeout: %s", vc.Timeout.Duration)
+ vc.Debugf("using timeout: %s", vc.Timeout)
- return true
+ return nil
}
-func (vc *VCSA) Check() bool {
+func (vc *VCSA) Check() error {
err := vc.client.Login()
if err != nil {
vc.Error(err)
- return false
+ return err
+ }
+
+ mx, err := vc.collect()
+ if err != nil {
+ vc.Error(err)
+ return err
+ }
+
+ if len(mx) == 0 {
+ return errors.New("no metrics collected")
}
- return len(vc.Collect()) > 0
+ return nil
}
func (vc *VCSA) Charts() *module.Charts {
diff --git a/src/go/collectors/go.d.plugin/modules/vcsa/vcsa_test.go b/src/go/collectors/go.d.plugin/modules/vcsa/vcsa_test.go
index 86185bfa2f..ccd659665b 100644
--- a/src/go/collectors/go.d.plugin/modules/vcsa/vcsa_test.go
+++ b/src/go/collectors/go.d.plugin/modules/vcsa/vcsa_test.go
@@ -4,77 +4,84 @@ package vcsa
import (
"errors"
+ "os"
"testing"
+ "github.com/netdata/netdata/go/go.d.plugin/agent/module"
+
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
-func testNewVCSA() *VCSA {
- vc := New()
- vc.URL = "https://127.0.0.1:38001"
- vc.Username = "user"
- vc.Password = "pass"
- return vc
-}
+var (
+ dataConfigJSON, _ = os.ReadFile("testdata/config.json")
+ dataConfigYAML, _ = os.ReadFile("testdata/config.yaml")
+)
-func TestNew(t *testing.T) {
- job := New()
+func Test_testDataIsValid(t *testing.T) {
+ for name, data := range map[string][]byte{
+ "dataConfigJSON": dataConfigJSON,
+ "dataConfigYAML": dataConfigYAML,
+ } {
+ require.NotNil(t, data, name)
+ }
+}
- assert.IsType(t, (*VCSA)(nil), job)
+func TestVCSA_ConfigurationSerialize(t *testing.T) {
+ module.TestConfigurationSerialize(t, &VCSA{}, dataConfigJSON, dataConfigYAML)
}
func TestVCSA_Init(t *testing.T) {
- job := testNewVCSA()
+ job := prepareVCSA()
- assert.True(t, job.Init())
+ assert.NoError(t, job.Init())
assert.NotNil(t, job.client)
}
func TestVCenter_InitErrorOnValidatingInitParameters(t *testing.T) {
job := New()
- assert.False(t, job.Init())
+ assert.Error(t, job.Init())
}
func TestVCenter_InitErrorOnCreatingClient(t *testing.T) {
- job := testNewVCSA()
+ job := prepareVCSA()
job.Client.TLSConfig.TLSCA = "testdata/tls"
- assert.False(t, job.Init())
+ assert.Error(t, job.Init())
}
func TestVCenter_Check(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
job.client = &mockVCenterHealthClient{}
- assert.True(t, job.Check())
+ assert.NoError(t, job.Check())
}
func TestVCenter_CheckErrorOnLogin(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
job.client = &mockVCenterHealthClient{
login: func() error { return errors.New("login mock error") },
}
- assert.False(t, job.Check())
+ assert.Error(t, job.Check())
}
func TestVCenter_CheckEnsureLoggedIn(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
mock := &mockVCenterHealthClient{}
job.client = mock
- assert.True(t, job.Check())
+ assert.NoError(t, job.Check())
assert.True(t, mock.loginCalls == 1)
}
func TestVCenter_Cleanup(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
mock := &mockVCenterHealthClient{}
job.client = mock
job.Cleanup()
@@ -83,7 +90,7 @@ func TestVCenter_Cleanup(t *testing.T) {
}
func TestVCenter_CleanupWithNilClient(t *testing.T) {
- job := testNewVCSA()
+ job := prepareVCSA()
assert.NotPanics(t, job.Cleanup)
}
@@ -93,8 +100,8 @@ func TestVCenter_Charts(t *testing.T) {
}
func TestVCenter_Collect(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
mock := &mockVCenterHealthClient{}
job.client = mock
@@ -152,8 +159,8 @@ func TestVCenter_Collect(t *testing.T) {
}
func TestVCenter_CollectEnsurePingIsCalled(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
mock := &mockVCenterHealthClient{}
job.client = mock
job.Collect()
@@ -162,8 +169,8 @@ func TestVCenter_CollectEnsurePingIsCalled(t *testing.T) {
}
func TestVCenter_CollectErrorOnPing(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
mock := &mockVCenterHealthClient{
ping: func() error { return errors.New("ping mock error") },
}
@@ -173,8 +180,8 @@ func TestVCenter_CollectErrorOnPing(t *testing.T) {
}
func TestVCenter_CollectErrorOnHealthCalls(t *testing.T) {
- job := testNewVCSA()
- require.True(t, job.Init())
+ job := prepareVCSA()
+ require.NoError(t, job.Init())
mock := &mockVCenterHealthClient{
applMgmt: func() (string, error) { return "", errors.New("applMgmt mock error") },
databaseStorage: func() (string, error) { return "", errors.New("databaseStorage mock error") },
@@ -190,6 +197,15 @@ func TestVCenter_CollectErrorOnHealthCalls(t *testing.T) {
assert.Zero(t, job.Collect())
}
+func prepareVCSA() *VCSA {
+ vc := New()
+ vc.URL = "https://127.0.0.1:38001"
+ vc.Username = "user"
+ vc.Password = "pass"
+
+ return vc
+}
+
type mockVCenterHealthClient struct {
login func() error
logout func() error
@@ -231,56 +247,56 @@ func (m *mockVCenterHealthClient) Ping() error {
return m.ping()
}
-func (m mockVCenterHealthClient) ApplMgmt() (string, error) {
+func (m *mockVCenterHealthClient) ApplMgmt() (string, error) {
if m.applMgmt == nil {
return "green", nil
}
return m.applMgmt()
}
-func (m mockVCenterHealthClient) DatabaseStorage() (string, error) {
+func (m *mockVCenterHealthClient) DatabaseStorage() (string, error) {
if m.databaseStorage == nil {
return "green", nil
}
return m.databaseStorage()
}
-func (m mockVCenterHealthClient) Load() (string, error) {
+func (m *mockVCenterHealthClient) Load() (string, error) {
if m.load == nil {
return "green", nil
}
return m.load()
}
-func (m mockVCenterHealthClient) Mem() (string, error) {
+func (m *mockVCenterHealthClient) Mem() (string, error) {
if m.mem == nil {
return "green", nil
}
return m.mem()
}
-func (m mockVCenterHealthClient) SoftwarePackages() (string, error) {
+func (m *mockVCenterHealthClient) SoftwarePackages() (string, error) {
if m.softwarePackages == nil {
return "green", nil
}
return m.softwarePackages()
}
-func (m mockVCenterHealthClient) Storage() (string, error) {
+func (m *mockVCenterHealthClient) Storage() (string, error) {
if m.storage == nil {
return "green", nil
}
return m.storage()
}
-func (m mockVCenterHealthClient) Swap() (string, error) {
+func (m *mockVCenterHealthClient) Swap() (string, error) {
if m.swap == nil {
return "green", nil
}
return m.swap()
}
-func (m mockVCenterHealthClient) System() (string, error) {
+func (m *mockVCenterHealthClient) System() (string, error) {
if m.system == nil {
return "green", nil
}