From 72917754b8d971262251bd8eacc37827eab5abfa Mon Sep 17 00:00:00 2001 From: Hardikl <83282894+Hardikl@users.noreply.github.com> Date: Mon, 17 Apr 2023 17:20:19 +0530 Subject: [PATCH] fix: handle interface api call in svm rest/zapi (#1912) * fix: handle interface api call in svm rest/zapi * fix: handled non-svm scoped rest/zapi calls in plugin --- cmd/collectors/rest/plugins/svm/svm.go | 227 ++++++++++++++++++++++- cmd/collectors/zapi/plugins/svm/svm.go | 152 ++++++++------- conf/rest/9.12.0/svm.yaml | 17 -- grafana/dashboards/cmode/compliance.json | 11 +- 4 files changed, 320 insertions(+), 87 deletions(-) diff --git a/cmd/collectors/rest/plugins/svm/svm.go b/cmd/collectors/rest/plugins/svm/svm.go index d3c7e56ac..0fc21a8b8 100644 --- a/cmd/collectors/rest/plugins/svm/svm.go +++ b/cmd/collectors/rest/plugins/svm/svm.go @@ -7,16 +7,24 @@ package svm import ( "github.com/netapp/harvest/v2/cmd/collectors" "github.com/netapp/harvest/v2/cmd/poller/plugin" + "github.com/netapp/harvest/v2/cmd/tools/rest" + "github.com/netapp/harvest/v2/pkg/conf" "github.com/netapp/harvest/v2/pkg/errs" "github.com/netapp/harvest/v2/pkg/matrix" "github.com/tidwall/gjson" "sort" "strings" + "time" ) type SVM struct { *plugin.AbstractPlugin - nsswitchInfo map[string]nsswitch + nsswitchInfo map[string]nsswitch + kerberosInfo map[string]string + fpolicyInfo map[string]fpolicy + iscsiServiceInfo map[string]string + iscsiCredentialInfo map[string]string + client *rest.Client } type nsswitch struct { @@ -24,17 +32,48 @@ type nsswitch struct { nssource []string } +type fpolicy struct { + name string + enable string +} + func New(p *plugin.AbstractPlugin) plugin.Plugin { return &SVM{AbstractPlugin: p} } +func (my *SVM) Init() error { + + var err error + + if err = my.InitAbc(); err != nil { + return err + } + + timeout, _ := time.ParseDuration(rest.DefaultTimeout) + if my.client, err = rest.New(conf.ZapiPoller(my.ParentParams), timeout, my.Auth); err != nil { + my.Logger.Error().Stack().Err(err).Msg("connecting") + return err + } + + if err = my.client.Init(5); err != nil { + return err + } + my.nsswitchInfo = make(map[string]nsswitch) + my.kerberosInfo = make(map[string]string) + my.fpolicyInfo = make(map[string]fpolicy) + my.iscsiServiceInfo = make(map[string]string) + my.iscsiCredentialInfo = make(map[string]string) + + return nil +} + func (my *SVM) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix, error) { var ( err error ) data := dataMap[my.Object] - // invoke nameservice-nsswitch-get-iter zapi and get nsswitch info + // update nsswitch info if my.nsswitchInfo, err = my.GetNSSwitchInfo(data); err != nil { if errs.IsRestErr(err, errs.APINotFound) { my.Logger.Debug().Err(err).Msg("Failed to collect nsswitch info") @@ -43,6 +82,42 @@ func (my *SVM) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix, error) } } + // invoke api/protocols/nfs/kerberos/interfaces rest and get nfs_kerberos_protocol_enabled + if my.kerberosInfo, err = my.GetKerberosConfig(); err != nil { + if errs.IsRestErr(err, errs.APINotFound) { + my.Logger.Debug().Err(err).Msg("Failed to collect kerberos config") + } else { + my.Logger.Error().Err(err).Msg("Failed to collect kerberos config") + } + } + + // invoke api/protocols/fpolicy rest and get fpolicy_enabled, fpolicy_name + if my.fpolicyInfo, err = my.GetFpolicy(); err != nil { + if errs.IsRestErr(err, errs.APINotFound) { + my.Logger.Debug().Err(err).Msg("Failed to collect fpolicy info") + } else { + my.Logger.Error().Err(err).Msg("Failed to collect fpolicy info") + } + } + + // invoke api/protocols/san/iscsi/services rest and get iscsi_service_enabled + if my.iscsiServiceInfo, err = my.GetIscsiServices(); err != nil { + if errs.IsRestErr(err, errs.APINotFound) { + my.Logger.Debug().Err(err).Msg("Failed to collect fpolicy info") + } else { + my.Logger.Error().Err(err).Msg("Failed to collect fpolicy info") + } + } + + // invoke api/protocols/san/iscsi/credentials rest and get iscsi_authentication_type + if my.iscsiCredentialInfo, err = my.GetIscsiCredentials(); err != nil { + if errs.IsRestErr(err, errs.APINotFound) { + my.Logger.Debug().Err(err).Msg("Failed to collect fpolicy info") + } else { + my.Logger.Error().Err(err).Msg("Failed to collect fpolicy info") + } + } + // update svm instance based on the above zapi response for _, svmInstance := range data.GetInstances() { svmName := svmInstance.GetLabel("svm") @@ -58,6 +133,27 @@ func (my *SVM) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix, error) svmInstance.SetLabel("ns_db", nsDB) collectors.SetNameservice(nsDB, nsSource, nisDomain, svmInstance) } + + // Update nfs_kerberos_protocol_enabled label in svm + if kerberosEnabled, ok := my.kerberosInfo[svmName]; ok { + svmInstance.SetLabel("nfs_kerberos_protocol_enabled", kerberosEnabled) + } + + // Update fpolicy_enabled, fpolicy_name label in svm + if fpolicyInfo, ok := my.fpolicyInfo[svmName]; ok { + svmInstance.SetLabel("fpolicy_enabled", fpolicyInfo.enable) + svmInstance.SetLabel("fpolicy_name", fpolicyInfo.name) + } + + // Update iscsi_service_enabled label in svm + if iscsiServiceEnabled, ok := my.iscsiServiceInfo[svmName]; ok { + svmInstance.SetLabel("iscsi_service_enabled", iscsiServiceEnabled) + } + + // Update iscsi_authentication_type label in svm + if iscsiAuthenticationType, ok := my.iscsiCredentialInfo[svmName]; ok { + svmInstance.SetLabel("iscsi_authentication_type", iscsiAuthenticationType) + } } return nil, nil } @@ -93,3 +189,130 @@ func (my *SVM) GetNSSwitchInfo(data *matrix.Matrix) (map[string]nsswitch, error) } return vserverNsswitchMap, nil } + +func (my *SVM) GetKerberosConfig() (map[string]string, error) { + var ( + result []gjson.Result + svmKerberosMap map[string]string + err error + ) + + svmKerberosMap = make(map[string]string) + query := "api/protocols/nfs/kerberos/interfaces" + kerberosFields := []string{"svm.name", "enabled"} + href := rest.BuildHref("", strings.Join(kerberosFields, ","), nil, "", "", "", "", query) + + if result, err = collectors.InvokeRestCall(my.client, href, my.Logger); err != nil { + return nil, err + } + + for _, kerberosConfig := range result { + enable := kerberosConfig.Get("enabled").String() + svmName := kerberosConfig.Get("svm.name").String() + if _, ok := svmKerberosMap[svmName]; !ok { + svmKerberosMap[svmName] = enable + } else { + // If any interface on the svm has kerberos on, then only set to true + if enable == "true" { + svmKerberosMap[svmName] = enable + } + } + } + + return svmKerberosMap, nil +} + +func (my *SVM) GetFpolicy() (map[string]fpolicy, error) { + var ( + result []gjson.Result + svmFpolicyMap map[string]fpolicy + err error + ) + + svmFpolicyMap = make(map[string]fpolicy) + query := "api/protocols/fpolicy" + fpolicyFields := []string{"svm.name", "policies.enabled", "policies.name"} + href := rest.BuildHref("", strings.Join(fpolicyFields, ","), nil, "", "", "", "", query) + + if result, err = collectors.InvokeRestCall(my.client, href, my.Logger); err != nil { + return nil, err + } + + for _, fpolicyData := range result { + fpolicyEnable := fpolicyData.Get("policies.enabled").String() + fpolicyName := fpolicyData.Get("policies.name").String() + svmName := fpolicyData.Get("svm.name").String() + if _, ok := svmFpolicyMap[svmName]; !ok { + svmFpolicyMap[svmName] = fpolicy{name: fpolicyName, enable: fpolicyEnable} + } else { + // If svm is already present, update the status value only if it is false + if svmFpolicyMap[svmName].enable == "false" { + svmFpolicyMap[svmName] = fpolicy{name: fpolicyName, enable: fpolicyEnable} + } + } + } + + return svmFpolicyMap, nil +} + +func (my *SVM) GetIscsiServices() (map[string]string, error) { + var ( + result []gjson.Result + svmIscsiServiceMap map[string]string + err error + ) + + svmIscsiServiceMap = make(map[string]string) + query := "api/protocols/san/iscsi/services" + iscsiServiceFields := []string{"svm.name", "enabled"} + href := rest.BuildHref("", strings.Join(iscsiServiceFields, ","), nil, "", "", "", "", query) + + if result, err = collectors.InvokeRestCall(my.client, href, my.Logger); err != nil { + return nil, err + } + + for _, iscsiData := range result { + iscsiServiceEnable := iscsiData.Get("enabled").String() + svmName := iscsiData.Get("svm.name").String() + if _, ok := svmIscsiServiceMap[svmName]; !ok { + svmIscsiServiceMap[svmName] = iscsiServiceEnable + } else { + // If svm is already present, update the map value only if previous value is false + if svmIscsiServiceMap[svmName] == "false" { + svmIscsiServiceMap[svmName] = iscsiServiceEnable + } + } + } + + return svmIscsiServiceMap, nil +} + +func (my *SVM) GetIscsiCredentials() (map[string]string, error) { + var ( + result []gjson.Result + svmIscsiCredentialMap map[string]string + err error + ) + + svmIscsiCredentialMap = make(map[string]string) + query := "api/protocols/san/iscsi/credentials" + iscsiCredentialFields := []string{"svm.name", "authentication_type"} + href := rest.BuildHref("", strings.Join(iscsiCredentialFields, ","), nil, "", "", "", "", query) + + if result, err = collectors.InvokeRestCall(my.client, href, my.Logger); err != nil { + return nil, err + } + + for _, iscsiData := range result { + authenticationType := iscsiData.Get("authentication_type").String() + svmName := iscsiData.Get("svm.name").String() + if _, ok := svmIscsiCredentialMap[svmName]; !ok { + svmIscsiCredentialMap[svmName] = authenticationType + } else { + // If svm is already present, update the map value with append this authenticationType to previous value + svmIscsiCredentialMap[svmName] = svmIscsiCredentialMap[svmName] + "," + authenticationType + } + } + + return svmIscsiCredentialMap, nil +} diff --git a/cmd/collectors/zapi/plugins/svm/svm.go b/cmd/collectors/zapi/plugins/svm/svm.go index 4aa48ce00..f87e7d7cd 100644 --- a/cmd/collectors/zapi/plugins/svm/svm.go +++ b/cmd/collectors/zapi/plugins/svm/svm.go @@ -221,77 +221,76 @@ func (my *SVM) Run(dataMap map[string]*matrix.Matrix) ([]*matrix.Matrix, error) my.Logger.Error().Err(err).Msg("Failed to collect kerberos config") } } + } - // update svm instance based on the above zapi response - for _, svmInstance := range data.GetInstances() { - svmName := svmInstance.GetLabel("svm") - - // Update audit_protocol_enabled label in svm - svmInstance.SetLabel("audit_protocol_enabled", my.auditProtocols[svmName]) + // update svm instance based on the above zapi response + for _, svmInstance := range data.GetInstances() { + svmName := svmInstance.GetLabel("svm") - // Update cifs_ntlm_enabled label in svm - if cifsData, ok := my.cifsProtocols[svmName]; ok { - svmInstance.SetLabel("cifs_ntlm_enabled", cifsData.cifsNtlmEnabled) - svmInstance.SetLabel("smb_encryption_required", cifsData.smbEncryption) - svmInstance.SetLabel("smb_signing_required", cifsData.smbSigning) - } + // Update audit_protocol_enabled label in svm + svmInstance.SetLabel("audit_protocol_enabled", my.auditProtocols[svmName]) - // Update nis_domain label in svm - svmInstance.SetLabel("nis_domain", my.nisInfo[svmName]) - - // Update nameservice_switch label in svm - if nsswitchInfo, ok := my.nsswitchInfo[svmName]; ok { - sort.Strings(nsswitchInfo.nsdb) - sort.Strings(nsswitchInfo.nssource) - nsDB := strings.Join(nsswitchInfo.nsdb, ",") - nsSource := strings.Join(nsswitchInfo.nssource, ",") - nisDomain := my.nisInfo[svmName] - svmInstance.SetLabel("ns_source", nsSource) - svmInstance.SetLabel("ns_db", nsDB) - collectors.SetNameservice(nsDB, nsSource, nisDomain, svmInstance) - } + // Update cifs_ntlm_enabled label in svm + if cifsData, ok := my.cifsProtocols[svmName]; ok { + svmInstance.SetLabel("cifs_ntlm_enabled", cifsData.cifsNtlmEnabled) + svmInstance.SetLabel("smb_encryption_required", cifsData.smbEncryption) + svmInstance.SetLabel("smb_signing_required", cifsData.smbSigning) + } - // Update cifs_protocol_enabled label in svm - if cifsEnable, ok := my.cifsEnabled[svmName]; ok { - svmInstance.SetLabel("cifs_protocol_enabled", strconv.FormatBool(cifsEnable)) - } + // Update nis_domain label in svm + svmInstance.SetLabel("nis_domain", my.nisInfo[svmName]) + + // Update nameservice_switch label in svm + if nsswitchInfo, ok := my.nsswitchInfo[svmName]; ok { + sort.Strings(nsswitchInfo.nsdb) + sort.Strings(nsswitchInfo.nssource) + nsDB := strings.Join(nsswitchInfo.nsdb, ",") + nsSource := strings.Join(nsswitchInfo.nssource, ",") + nisDomain := my.nisInfo[svmName] + svmInstance.SetLabel("ns_source", nsSource) + svmInstance.SetLabel("ns_db", nsDB) + collectors.SetNameservice(nsDB, nsSource, nisDomain, svmInstance) + } - // Update nfs_protocol_enabled label in svm - if nfsEnable, ok := my.nfsEnabled[svmName]; ok { - svmInstance.SetLabel("nfs_protocol_enabled", nfsEnable) - } + // Update cifs_protocol_enabled label in svm + if cifsEnable, ok := my.cifsEnabled[svmName]; ok { + svmInstance.SetLabel("cifs_protocol_enabled", strconv.FormatBool(cifsEnable)) + } - // Update ciphers label in svm - if sshInfo, ok := my.sshData[svmName]; ok { - svmInstance.SetLabel("ciphers", sshInfo) - } + // Update nfs_protocol_enabled label in svm + if nfsEnable, ok := my.nfsEnabled[svmName]; ok { + svmInstance.SetLabel("nfs_protocol_enabled", nfsEnable) + } - // Update iscsi_authentication_type label in svm - if authType, ok := my.iscsiAuth[svmName]; ok { - svmInstance.SetLabel("iscsi_authentication_type", authType) - } + // Update ciphers label in svm + if sshInfo, ok := my.sshData[svmName]; ok { + svmInstance.SetLabel("ciphers", sshInfo) + } - // Update iscsi_service_enabled label in svm - if available, ok := my.iscsiService[svmName]; ok { - svmInstance.SetLabel("iscsi_service_enabled", available) - } + // Update iscsi_authentication_type label in svm + if authType, ok := my.iscsiAuth[svmName]; ok { + svmInstance.SetLabel("iscsi_authentication_type", authType) + } - // Update fpolicy_enabled, fpolicy_name label in svm - if fpolicyData, ok := my.fpolicyData[svmName]; ok { - svmInstance.SetLabel("fpolicy_enabled", fpolicyData.enable) - svmInstance.SetLabel("fpolicy_name", fpolicyData.name) - } + // Update iscsi_service_enabled label in svm + if available, ok := my.iscsiService[svmName]; ok { + svmInstance.SetLabel("iscsi_service_enabled", available) + } - // Update ldap_session_security label in svm - if ldapSessionSecurity, ok := my.ldapData[svmName]; ok { - svmInstance.SetLabel("ldap_session_security", ldapSessionSecurity) - } + // Update fpolicy_enabled, fpolicy_name label in svm + if fpolicyData, ok := my.fpolicyData[svmName]; ok { + svmInstance.SetLabel("fpolicy_enabled", fpolicyData.enable) + svmInstance.SetLabel("fpolicy_name", fpolicyData.name) + } - // Update nfs_kerberos_protocol_enabled label in svm - if kerberosEnabled, ok := my.kerberosConfig[svmName]; ok { - svmInstance.SetLabel("nfs_kerberos_protocol_enabled", kerberosEnabled) - } + // Update ldap_session_security label in svm + if ldapSessionSecurity, ok := my.ldapData[svmName]; ok { + svmInstance.SetLabel("ldap_session_security", ldapSessionSecurity) + } + // Update nfs_kerberos_protocol_enabled label in svm + if kerberosEnabled, ok := my.kerberosConfig[svmName]; ok { + svmInstance.SetLabel("nfs_kerberos_protocol_enabled", kerberosEnabled) } } @@ -538,7 +537,12 @@ func (my *SVM) GetIscsiInitiatorAuth() (map[string]string, error) { for _, iscsiSecurityEntry := range result { authType := iscsiSecurityEntry.GetChildContentS("auth-type") svmName := iscsiSecurityEntry.GetChildContentS("vserver") - vserverIscsiAuthMap[svmName] = authType + if _, ok := vserverIscsiAuthMap[svmName]; !ok { + vserverIscsiAuthMap[svmName] = authType + } else { + // If svm is already present, update the map value with append this authenticationType to previous value + vserverIscsiAuthMap[svmName] = vserverIscsiAuthMap[svmName] + "," + authType + } } return vserverIscsiAuthMap, nil } @@ -567,7 +571,14 @@ func (my *SVM) GetIscsiService() (map[string]string, error) { for _, iscsiService := range result { available := iscsiService.GetChildContentS("is-available") svmName := iscsiService.GetChildContentS("vserver") - vserverIscsiServiceMap[svmName] = available + if _, ok := vserverIscsiServiceMap[svmName]; !ok { + vserverIscsiServiceMap[svmName] = available + } else { + // If svm is already present, update the map value only if previous value is false + if vserverIscsiServiceMap[svmName] == "false" { + vserverIscsiServiceMap[svmName] = available + } + } } return vserverIscsiServiceMap, nil } @@ -597,7 +608,14 @@ func (my *SVM) GetFpolicy() (map[string]fpolicy, error) { name := fpolicyData.GetChildContentS("policy-name") enable := fpolicyData.GetChildContentS("status") svmName := fpolicyData.GetChildContentS("vserver") - vserverFpolicyMap[svmName] = fpolicy{name: name, enable: enable} + if _, ok := vserverFpolicyMap[svmName]; !ok { + vserverFpolicyMap[svmName] = fpolicy{name: name, enable: enable} + } else { + // If svm is already present, update the status value only if it is false + if vserverFpolicyMap[svmName].enable == "false" { + vserverFpolicyMap[svmName] = fpolicy{name: name, enable: enable} + } + } } return vserverFpolicyMap, nil } @@ -655,7 +673,15 @@ func (my *SVM) GetKerberosConfig() (map[string]string, error) { for _, kerberosConfig := range result { enable := kerberosConfig.GetChildContentS("is-kerberos-enabled") svmName := kerberosConfig.GetChildContentS("vserver") - vserverKerberosMap[svmName] = enable + if _, ok := vserverKerberosMap[svmName]; !ok { + vserverKerberosMap[svmName] = enable + } else { + // If any interface on the svm has kerberos on, then only set to true + if enable == "true" { + vserverKerberosMap[svmName] = enable + } + } + } return vserverKerberosMap, nil } diff --git a/conf/rest/9.12.0/svm.yaml b/conf/rest/9.12.0/svm.yaml index c42cce2c3..d164305d5 100644 --- a/conf/rest/9.12.0/svm.yaml +++ b/conf/rest/9.12.0/svm.yaml @@ -33,11 +33,6 @@ endpoints: counters: - ^^svm.name => svm - ^enabled => audit_protocol_enabled - - query: api/protocols/fpolicy # need to test - counters: - - ^^svm.name => svm - - ^policies.enabled => fpolicy_enabled - - ^policies.name => fpolicy_name - query: api/name-services/nis counters: - ^^svm.name => svm @@ -46,18 +41,6 @@ endpoints: counters: - ^^svm.name => svm - ^session_security => ldap_session_security - - query: api/protocols/nfs/kerberos/interfaces - counters: - - ^^svm.name => svm - - ^enabled => nfs_kerberos_protocol_enabled - - query: api/protocols/san/iscsi/credentials - counters: - - ^^svm.name => svm - - ^authentication_type => iscsi_authentication_type - - query: api/protocols/san/iscsi/services - counters: - - ^^svm.name => svm - - ^enabled => iscsi_service_enabled - query: api/private/cli/vserver/cifs/server/security counters: - ^^vserver => svm diff --git a/grafana/dashboards/cmode/compliance.json b/grafana/dashboards/cmode/compliance.json index a5048ea80..2af13f582 100644 --- a/grafana/dashboards/cmode/compliance.json +++ b/grafana/dashboards/cmode/compliance.json @@ -2407,13 +2407,14 @@ "id": "mappings", "value": [ { + "type": "regex", "options": { - "chap": { - "index": 0, - "text": "Enabled" + "pattern": ".*chap.*", + "result": { + "text": "Enabled", + "index": 0 } - }, - "type": "value" + } }, { "options": {