diff options
author | Ilya Mashchenko <ilya@netdata.cloud> | 2024-03-05 16:40:19 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-03-05 16:40:19 +0200 |
commit | 4c1adba5073294537f7233634ad15684018a42cf (patch) | |
tree | f2fc7526e8cc585187e4006c4126f42c0f54b3a1 /src/go/collectors/go.d.plugin/modules/vcsa | |
parent | d8827d1e5ff927623d16b2e67ad9123e5f5b24ea (diff) |
go.d.plugin dyncfgv2 (#17064)
Diffstat (limited to 'src/go/collectors/go.d.plugin/modules/vcsa')
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 } |