Repository: NetApp/harvest
Pull request #984 (2022-04-26 11:14:54)

fix: ignore transient volumes
Below details from the Netapp_Harvest_IAG_1.X.pdf

****C.** Use a blacklist to prevent visibility of temporary volumes [optional]**
Harvest will discover all instances of objects such as lifs, volumes, and luns on the cluster. Some of these instances may be temporary, such as those used by backup jobs, and add undesired clutter and storage consumption. Graphite provides the ability to blacklist (block) incoming metrics that match a regular expression string and this feature can be used to block metrics for these temporary instances.
The following steps can be used to block metrics on temporary volumes that are often created by NetApp and NetApp partner software integrations:

1. Login the graphite host and if not logged in as the root superuser, become root using sudo:
```
[user@host ~]# sudo -i
```

2. Use a text editor (nano, vi) to edit the blacklist.conf file. Depending on your installation the location can vary, but is typically one of:
```
[root@host ~]# nano /etc/carbon/blacklist.conf
or
[root@host ~]# nano /opt/graphite/conf/blacklist.conf
```

3. Add the following contents to this file, save, and exit to the command prompt.
```
#
# Exclusion for SnapProtect/CommVault Intellisnap
# Clone volumes gets a “_CVclone” suffix
# ^netapp\.(capacity|perf7?)\..+\.vol\..+_CVclone\..+
#
# Exclusion for SnapCenter
# Clone volumes gets a “DDMMYYhhmmss” suffix
# ^netapp\.(capacity|perf)\..+\.vol\..+(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d[0- 9]{6}\..+
#
# Exclusion for SnapCreator
# This is from creating a clone manually in SnapCreator
# Clone volume gets a “cl_” prefix and a “_YYYYMMDDhhmmss” suffix
#
^netapp\.(capacity|perf7?)\..+\.vol\.cl_.+_(19|20)\d\d(0[1-9]|1[012])( 0[1-9]|[12][0- 9]|3[01])[0-9]{6}\..+
#
# Exclusion for SnapDrive/SnapManager
# Clone volumes gets a “sdw_cl_” prefix
# ^netapp\.(capacity|perf7?)\..+\.vol\.sdw_cl_.+\..+
#
# Exclusion for Metadata volumes that may also clutter menus. #
# CRS volumes in SVM-DR or MetroCluster get a “MDV_CRS_” prefix
# Audit volumes get a “MDV_aud_” prefix # ^netapp\.(perf)\..+\.vol\.MDV_CRS_.+\..+ ^netapp\.(perf)\..+\.vol\.MDV_aud_.+\..+
```

**As per the 1.X doc, these are not ignored by default, They can be ignored based on the above blacklist file.**


--> No transient volumes in my local setup, but MDV_CRS and MDV_aud. Tested them with given regex.

Hardikl: I will check perf and REST would need this filter or not and will update PR.

Patch:
diff --git a/cmd/collectors/rest/plugins/util.go b/cmd/collectors/commonutils.go
similarity index 60%
rename from cmd/collectors/rest/plugins/util.go
rename to cmd/collectors/commonutils.go
index 0d540818..7b38251a 100644
--- a/cmd/collectors/rest/plugins/util.go
+++ b/cmd/collectors/commonutils.go
@@ -1,15 +1,95 @@
-package plugins
+package collectors
 
 import (
 	"encoding/json"
 	"github.com/tidwall/gjson"
 	"goharvest2/cmd/tools/rest"
+	"goharvest2/pkg/api/ontapi/zapi"
 	"goharvest2/pkg/errors"
 	"goharvest2/pkg/logging"
 	"goharvest2/pkg/matrix"
+	"goharvest2/pkg/tree/node"
 	"strings"
+	"time"
 )
 
+func InvokeRestCall(client *rest.Client, query string, href string, logger *logging.Logger) ([]gjson.Result, error) {
+	var (
+		records []interface{}
+		content []byte
+		err     error
+	)
+
+	err = rest.FetchData(client, href, &records)
+	if err != nil {
+		logger.Error().Stack().Err(err).Str("href", href).Msg("Failed to fetch data")
+		return []gjson.Result{}, err
+	}
+
+	all := rest.Pagination{
+		Records:    records,
+		NumRecords: len(records),
+	}
+
+	content, err = json.Marshal(all)
+	if err != nil {
+		logger.Error().Err(err).Str("ApiPath", query).Msg("Unable to marshal rest pagination")
+		return []gjson.Result{}, err
+	}
+
+	if !gjson.ValidBytes(content) {
+		logger.Error().Err(err).Str("Api", query).Msg("Invalid json")
+		return []gjson.Result{}, errors.New(errors.API_RESPONSE, "Invalid json")
+	}
+
+	results := gjson.GetManyBytes(content, "num_records", "records")
+	numRecords := results[0]
+	if numRecords.Int() == 0 {
+		return []gjson.Result{}, errors.New(errors.ERR_NO_INSTANCE, "no "+query+" instances on cluster")
+	}
+
+	return results[1].Array(), nil
+}
+
+func InvokeZapiCall(client *zapi.Client, request *node.Node, logger *logging.Logger, tag string) ([]*node.Node, string, error) {
+
+	var (
+		result   *node.Node
+		response []*node.Node
+		newTag   string
+		err      error
+	)
+
+	if tag != "" {
+		if result, newTag, err = client.InvokeBatchRequest(request, tag); err != nil {
+			return nil, "", err
+		}
+	} else {
+		if result, err = client.InvokeRequest(request); err != nil {
+			return nil, "", err
+		}
+	}
+
+	if result == nil {
+		return nil, "", nil
+	}
+
+	if x := result.GetChildS("attributes-list"); x != nil {
+		response = x.GetChildren()
+	} else if y := result.GetChildS("attributes"); y != nil {
+		// Check for non-list response
+		response = y.GetChildren()
+	}
+
+	if len(response) == 0 {
+		return nil, "", nil
+	}
+
+	logger.Debug().Int("object", len(response)).Msg("fetching")
+
+	return response, newTag, nil
+}
+
 func UpdateProtectedFields(instance *matrix.Instance) {
 
 	// check for group_type
@@ -66,40 +146,43 @@ func UpdateProtectedFields(instance *matrix.Instance) {
 	}
 }
 
-func InvokeRestCall(client *rest.Client, query string, href string, logger *logging.Logger) ([]gjson.Result, error) {
-	var (
-		records []interface{}
-		content []byte
-		err     error
-	)
+func SetNameservice(ns_db, ns_source, nis_domain string, instance *matrix.Instance) {
+	requiredNSDb := false
+	requiredNSSource := false
 
-	err = rest.FetchData(client, href, &records)
-	if err != nil {
-		logger.Error().Stack().Err(err).Str("href", href).Msg("Failed to fetch data")
-		return []gjson.Result{}, err
+	if strings.Contains(ns_db, "passwd") || strings.Contains(ns_db, "group") || strings.Contains(ns_db, "netgroup") {
+		requiredNSDb = true
+		if strings.Contains(ns_source, "nis") {
+			requiredNSSource = true
+		}
 	}
 
-	all := rest.Pagination{
-		Records:    records,
-		NumRecords: len(records),
+	if nis_domain != "" && requiredNSDb && requiredNSSource {
+		instance.SetLabel("nis_authentication_enabled", "true")
+	} else {
+		instance.SetLabel("nis_authentication_enabled", "false")
 	}
+}
 
-	content, err = json.Marshal(all)
-	if err != nil {
-		logger.Error().Err(err).Str("ApiPath", query).Msg("Unable to marshal rest pagination")
-		return []gjson.Result{}, err
-	}
+func SetPluginInterval(parentParams *node.Node, params *node.Node, logger *logging.Logger, defaultDataPollDuration time.Duration, defaultPluginDuration time.Duration) (int, error) {
 
-	if !gjson.ValidBytes(content) {
-		logger.Error().Err(err).Str("Api", query).Msg("Invalid json")
-		return []gjson.Result{}, errors.New(errors.API_RESPONSE, "Invalid json")
-	}
+	volumeDataInterval := GetDataInterval(parentParams, defaultDataPollDuration)
+	pluginDataInterval := GetDataInterval(params, defaultPluginDuration)
+	logger.Debug().Float64("VolumeDataInterval", volumeDataInterval).Float64("PluginDataInterval", pluginDataInterval).Msg("Poll interval duration")
+	pluginInvocationRate := int(pluginDataInterval / volumeDataInterval)
 
-	results := gjson.GetManyBytes(content, "num_records", "records")
-	numRecords := results[0]
-	if numRecords.Int() == 0 {
-		return []gjson.Result{}, errors.New(errors.ERR_NO_INSTANCE, "no "+query+" instances on cluster")
-	}
+	return pluginInvocationRate, nil
+}
 
-	return results[1].Array(), nil
+func GetDataInterval(param *node.Node, defaultInterval time.Duration) float64 {
+	schedule := param.GetChildS("schedule")
+	if schedule != nil {
+		dataInterval := schedule.GetChildContentS("data")
+		if dataInterval != "" {
+			if durationVal, err := time.ParseDuration(dataInterval); err == nil {
+				return durationVal.Seconds()
+			}
+		}
+	}
+	return defaultInterval.Seconds()
 }
diff --git a/cmd/collectors/rest/plugins/certificate/certificate.go b/cmd/collectors/rest/plugins/certificate/certificate.go
index efd788ec..49d82abd 100644
--- a/cmd/collectors/rest/plugins/certificate/certificate.go
+++ b/cmd/collectors/rest/plugins/certificate/certificate.go
@@ -8,7 +8,7 @@ import (
 	"crypto/x509"
 	"encoding/pem"
 	"github.com/tidwall/gjson"
-	"goharvest2/cmd/collectors/rest/plugins"
+	"goharvest2/cmd/collectors"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/cmd/tools/rest"
 	"goharvest2/pkg/conf"
@@ -213,7 +213,7 @@ func (my *Certificate) GetAdminVserver() (string, error) {
 	query := "api/private/cli/vserver"
 	href := rest.BuildHref("", "type", []string{"type=admin"}, "", "", "", "", query)
 
-	if result, err = plugins.InvokeRestCall(my.client, query, href, my.Logger); err != nil {
+	if result, err = collectors.InvokeRestCall(my.client, query, href, my.Logger); err != nil {
 		return "", err
 	}
 
@@ -235,7 +235,7 @@ func (my *Certificate) GetSecuritySsl(adminSvm string) (string, error) {
 	query := "api/private/cli/security/ssl"
 	href := rest.BuildHref("", "serial", []string{"vserver=" + adminSvm}, "", "", "", "", query)
 
-	if result, err = plugins.InvokeRestCall(my.client, query, href, my.Logger); err != nil {
+	if result, err = collectors.InvokeRestCall(my.client, query, href, my.Logger); err != nil {
 		return "", err
 	}
 
diff --git a/cmd/collectors/rest/plugins/qtree/qtree.go b/cmd/collectors/rest/plugins/qtree/qtree.go
index b6833b59..c1bbf2d8 100644
--- a/cmd/collectors/rest/plugins/qtree/qtree.go
+++ b/cmd/collectors/rest/plugins/qtree/qtree.go
@@ -6,7 +6,7 @@ package qtree
 
 import (
 	"github.com/tidwall/gjson"
-	"goharvest2/cmd/collectors/rest/plugins"
+	"goharvest2/cmd/collectors"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/cmd/tools/rest"
 	"goharvest2/pkg/conf"
@@ -119,7 +119,7 @@ func (my *Qtree) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 
 	href := rest.BuildHref("", "*", nil, "", "", "", "", my.query)
 
-	if result, err = plugins.InvokeRestCall(my.client, my.query, href, my.Logger); err != nil {
+	if result, err = collectors.InvokeRestCall(my.client, my.query, href, my.Logger); err != nil {
 		return nil, err
 	}
 
diff --git a/cmd/collectors/rest/plugins/snapmirror/snapmirror.go b/cmd/collectors/rest/plugins/snapmirror/snapmirror.go
index 7c893d48..a3567fb2 100644
--- a/cmd/collectors/rest/plugins/snapmirror/snapmirror.go
+++ b/cmd/collectors/rest/plugins/snapmirror/snapmirror.go
@@ -5,7 +5,7 @@ package snapmirror
 
 import (
 	"github.com/tidwall/gjson"
-	"goharvest2/cmd/collectors/rest/plugins"
+	"goharvest2/cmd/collectors"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/cmd/tools/rest"
 	"goharvest2/pkg/conf"
@@ -81,7 +81,7 @@ func (my *SnapMirror) updateNodeCache() error {
 	my.svmVolToNode = make(map[string]string)
 	href := rest.BuildHref("", "node", nil, "", "", "", "", my.query)
 
-	if result, err = plugins.InvokeRestCall(my.client, my.query, href, my.Logger); err != nil {
+	if result, err = collectors.InvokeRestCall(my.client, my.query, href, my.Logger); err != nil {
 		return err
 	}
 
@@ -110,6 +110,6 @@ func (my *SnapMirror) updateSMLabels(data *matrix.Matrix) {
 		}
 
 		// update the protectedBy and protectionSourceType fields and derivedRelationshipType in snapmirror_labels
-		plugins.UpdateProtectedFields(instance)
+		collectors.UpdateProtectedFields(instance)
 	}
 }
diff --git a/cmd/collectors/rest/plugins/svm/svm.go b/cmd/collectors/rest/plugins/svm/svm.go
index a9aaf28d..01f5382a 100644
--- a/cmd/collectors/rest/plugins/svm/svm.go
+++ b/cmd/collectors/rest/plugins/svm/svm.go
@@ -5,6 +5,8 @@
 package svm
 
 import (
+	"github.com/tidwall/gjson"
+	"goharvest2/cmd/collectors"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/pkg/matrix"
 	"strings"
@@ -12,6 +14,12 @@ import (
 
 type SVM struct {
 	*plugin.AbstractPlugin
+	nsswitchInfo map[string]nsswitch
+}
+
+type nsswitch struct {
+	nsdb     []string
+	nssource []string
 }
 
 func New(p *plugin.AbstractPlugin) plugin.Plugin {
@@ -19,29 +27,61 @@ func New(p *plugin.AbstractPlugin) plugin.Plugin {
 }
 
 func (my *SVM) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
-	my.setNameservice(data)
+	var (
+		err error
+	)
+
+	// invoke nameservice-nsswitch-get-iter zapi and get nsswitch info
+	if my.nsswitchInfo, err = my.GetNSSwitchInfo(data); err != nil {
+		my.Logger.Warn().Stack().Err(err).Msg("Failed to collect nsswitch info")
+		//return nil, nil
+	}
+
+	// update svm instance based on the above zapi response
+	for _, svmInstance := range data.GetInstances() {
+		svmName := svmInstance.GetLabel("svm")
+
+		// Update nameservice_switch and nis_domain label in svm
+		if nsswitchInfo, ok := my.nsswitchInfo[svmName]; ok {
+			ns_db := strings.Join(nsswitchInfo.nsdb, ",")
+			ns_source := strings.Join(nsswitchInfo.nssource, ",")
+			nis_domain := svmInstance.GetLabel("nis_domain")
+			svmInstance.SetLabel("ns_source", ns_source)
+			svmInstance.SetLabel("ns_db", ns_db)
+			collectors.SetNameservice(ns_db, ns_source, nis_domain, svmInstance)
+		}
+	}
 	return nil, nil
 }
 
-func (my *SVM) setNameservice(data *matrix.Matrix) {
-	for _, instance := range data.GetInstances() {
-		requiredNSDb := false
-		requiredNSSource := false
-		ns := instance.GetLabel("nameservice_switch")
-		nisDomain := instance.GetLabel("nis_domain")
-
-		if strings.Contains(ns, "passwd") || strings.Contains(ns, "group") || strings.Contains(ns, "netgroup") {
-			requiredNSDb = true
-			if strings.Contains(ns, "nis") {
-				requiredNSSource = true
-			}
-		}
+func (my *SVM) GetNSSwitchInfo(data *matrix.Matrix) (map[string]nsswitch, error) {
 
-		if nisDomain != "" && requiredNSDb && requiredNSSource {
-			instance.SetLabel("nis_authentication_enabled", "true")
-		} else {
-			instance.SetLabel("nis_authentication_enabled", "false")
-		}
+	var (
+		vserverNsswitchMap map[string]nsswitch
+		ns                 nsswitch
+		ok                 bool
+	)
+
+	vserverNsswitchMap = make(map[string]nsswitch)
+
+	for _, svmInstance := range data.GetInstances() {
+		svmName := svmInstance.GetLabel("svm")
+		nsswitchConfig := svmInstance.GetLabel("nameservice_switch")
 
+		config := gjson.Result{Type: gjson.JSON, Raw: nsswitchConfig}
+		replaceStr := strings.NewReplacer("[", "", "]", "", "\"", "")
+
+		for nsdb, nssource := range config.Map() {
+			nssourcelist := replaceStr.Replace(nssource.String())
+
+			if ns, ok = vserverNsswitchMap[svmName]; ok {
+				ns.nsdb = append(ns.nsdb, nsdb)
+				ns.nssource = append(ns.nssource, nssourcelist)
+			} else {
+				ns = nsswitch{nsdb: []string{nsdb}, nssource: []string{nssourcelist}}
+			}
+			vserverNsswitchMap[svmName] = ns
+		}
 	}
+	return vserverNsswitchMap, nil
 }
diff --git a/cmd/collectors/rest/plugins/volume/volume.go b/cmd/collectors/rest/plugins/volume/volume.go
index 49024dda..4547e519 100644
--- a/cmd/collectors/rest/plugins/volume/volume.go
+++ b/cmd/collectors/rest/plugins/volume/volume.go
@@ -6,20 +6,19 @@ package volume
 
 import (
 	"github.com/tidwall/gjson"
-	"goharvest2/cmd/collectors/rest/plugins"
+	"goharvest2/cmd/collectors"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/cmd/tools/rest"
 	"goharvest2/pkg/conf"
 	"goharvest2/pkg/dict"
 	"goharvest2/pkg/matrix"
-	"goharvest2/pkg/tree/node"
 	"strconv"
 	"strings"
 	"time"
 )
 
-const DefaultPluginDuration = 1800 * time.Second
-const DefaultDataPollDuration = 180 * time.Second
+const DefaultPluginDuration = 30 * time.Minute
+const DefaultDataPollDuration = 3 * time.Minute
 
 type Volume struct {
 	*plugin.AbstractPlugin
@@ -70,7 +69,7 @@ func (my *Volume) Init() error {
 	my.aggrsMap = make(map[string]string)
 
 	// Assigned the value to currentVal so that plugin would be invoked first time to populate cache.
-	if my.currentVal, err = my.setPluginInterval(); err != nil {
+	if my.currentVal, err = collectors.SetPluginInterval(my.ParentParams, my.Params, my.Logger, DefaultDataPollDuration, DefaultPluginDuration); err != nil {
 		my.Logger.Error().Err(err).Stack().Msg("Failed while setting the plugin interval")
 		return err
 	}
@@ -114,31 +113,6 @@ func (my *Volume) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 	return nil, nil
 }
 
-func (my *Volume) setPluginInterval() (int, error) {
-
-	volumeDataInterval := my.getDataInterval(my.ParentParams, DefaultDataPollDuration)
-	pluginDataInterval := my.getDataInterval(my.Params, DefaultPluginDuration)
-	my.Logger.Debug().Float64("VolumeDataInterval", volumeDataInterval).Float64("PluginDataInterval", pluginDataInterval).Msg("Poll interval duration")
-	my.pluginInvocationRate = int(pluginDataInterval / volumeDataInterval)
-
-	return my.pluginInvocationRate, nil
-}
-
-func (my *Volume) getDataInterval(param *node.Node, defaultInterval time.Duration) float64 {
-	var dataIntervalStr = ""
-	schedule := param.GetChildS("schedule")
-	if schedule != nil {
-		dataInterval := schedule.GetChildS("data")
-		if dataInterval != nil {
-			dataIntervalStr = dataInterval.GetContentS()
-			if durationVal, err := time.ParseDuration(dataIntervalStr); err == nil {
-				return durationVal.Seconds()
-			}
-		}
-	}
-	return defaultInterval.Seconds()
-}
-
 func (my *Volume) GetSnapMirrors() (map[string][]*matrix.Instance, map[string]*matrix.Instance, error) {
 	var (
 		result []gjson.Result
@@ -151,7 +125,7 @@ func (my *Volume) GetSnapMirrors() (map[string][]*matrix.Instance, map[string]*m
 	snapmirrorData := matrix.New(my.Parent+".SnapMirror", "sm", "sm")
 	href := rest.BuildHref("", strings.Join(my.snapmirrorFields, ","), nil, "", "", "", "", my.query)
 
-	if result, err = plugins.InvokeRestCall(my.client, my.query, href, my.Logger); err != nil {
+	if result, err = collectors.InvokeRestCall(my.client, my.query, href, my.Logger); err != nil {
 		return nil, nil, err
 	}
 
@@ -186,7 +160,7 @@ func (my *Volume) GetSnapMirrors() (map[string][]*matrix.Instance, map[string]*m
 		instance.SetLabel("destination_svm", destinationSvm)
 
 		// Update the protectedBy and protectionSourceType fields in snapmirror
-		plugins.UpdateProtectedFields(instance)
+		collectors.UpdateProtectedFields(instance)
 
 		// Update source snapmirror and destination snapmirror info in maps
 		if relationshipType == "data_protection" || relationshipType == "extended_data_protection" || relationshipType == "vault" || relationshipType == "xdp" {
@@ -307,7 +281,7 @@ func (my *Volume) getDiskData() ([]gjson.Result, error) {
 	query := "api/storage/disks"
 	href := rest.BuildHref("", strings.Join(diskFields, ","), []string{"protection_mode=!data|full"}, "", "", "", "", query)
 
-	if result, err = plugins.InvokeRestCall(my.client, query, href, my.Logger); err != nil {
+	if result, err = collectors.InvokeRestCall(my.client, query, href, my.Logger); err != nil {
 		return nil, err
 	}
 	return result, nil
diff --git a/cmd/collectors/restperf/restperf.go b/cmd/collectors/restperf/restperf.go
index 1648d10b..6afef681 100644
--- a/cmd/collectors/restperf/restperf.go
+++ b/cmd/collectors/restperf/restperf.go
@@ -24,6 +24,21 @@ const (
 	BILLION       = 1_000_000_000
 )
 
+var qosQuery = "api/cluster/counter/tables/qos"
+var qosVolumeQuery = "api/cluster/counter/tables/qos_volume"
+var qosDetailQuery = "api/cluster/counter/tables/qos_detail"
+var qosDetailVolumeQuery = "api/cluster/counter/tables/qos_detail_volume"
+var qosWorkloadQuery = "api/storage/qos/workloads"
+
+var qosQueries = map[string]string{
+	qosQuery:       qosQuery,
+	qosVolumeQuery: qosVolumeQuery,
+}
+var qosDetailQueries = map[string]string{
+	qosDetailQuery:       qosDetailQuery,
+	qosDetailVolumeQuery: qosDetailVolumeQuery,
+}
+
 type RestPerf struct {
 	*rest2.Rest // provides: AbstractCollector, Client, Object, Query, TemplateFn, TemplateType
 	perfProp    *perfProp
@@ -41,6 +56,7 @@ type perfProp struct {
 	isCacheEmpty  bool
 	counterInfo   map[string]*counter
 	latencyIoReqd int
+	qosLabels     map[string]string
 }
 
 type metricResponse struct {
@@ -92,11 +108,36 @@ func (r *RestPerf) Init(a *collector.AbstractCollector) error {
 		return err
 	}
 
+	if err = r.InitQOSLabels(); err != nil {
+		return err
+	}
+
 	r.Logger.Info().Str("count", strconv.Itoa(len(r.Matrix.GetMetrics()))).Msg("initialized cache with metrics")
 
 	return nil
 }
 
+func (r *RestPerf) InitQOSLabels() error {
+	if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) {
+		if qosLabels := r.Params.GetChildS("qos_labels"); qosLabels == nil {
+			return errors.New(errors.MISSING_PARAM, "qos_labels")
+		} else {
+			r.perfProp.qosLabels = make(map[string]string)
+			for _, label := range qosLabels.GetAllChildContentS() {
+
+				display := strings.ReplaceAll(label, "-", "_")
+				before, after, found := strings.Cut(label, "=>")
+				if found {
+					label = strings.TrimSpace(before)
+					display = strings.TrimSpace(after)
+				}
+				r.perfProp.qosLabels[label] = display
+			}
+		}
+	}
+	return nil
+}
+
 func (r *RestPerf) InitMatrix() error {
 	//init perf properties
 	r.perfProp.latencyIoReqd = r.loadParamInt("latency_io_reqd", latencyIoReqd)
@@ -243,6 +284,11 @@ func (r *RestPerf) PollCounter() (*matrix.Matrix, error) {
 		m.SetExportable(false)
 	}
 
+	_, err = r.processWorkLoadCounter()
+	if err != nil {
+		return r.Matrix, err
+	}
+
 	return r.Matrix, nil
 }
 
@@ -295,7 +341,7 @@ func parseMetricResponse(instanceData gjson.Result, metric string) *metricRespon
 	return &metricResponse{}
 }
 
-// override counter property
+// GetOverride override counter property
 func (r *RestPerf) GetOverride(counter string) string {
 	if o := r.Params.GetChildS("override"); o != nil {
 		return o.GetChildContentS(counter)
@@ -303,15 +349,102 @@ func (r *RestPerf) GetOverride(counter string) string {
 	return ""
 }
 
+func (r *RestPerf) processWorkLoadCounter() (*matrix.Matrix, error) {
+	var err error
+	// for these two objects, we need to create latency/ops counters for each of the workload layers
+	// their original counters will be discarded
+	if isWorkloadDetailObject(r.Prop.Query) {
+
+		for name, metric := range r.Prop.Metrics {
+			metr, ok := r.Matrix.GetMetrics()[name]
+			if !ok {
+				if metr, err = r.Matrix.NewMetricFloat64(name); err != nil {
+					r.Logger.Error().Err(err).
+						Str("name", name).
+						Msg("NewMetricFloat64")
+				}
+			}
+			metr.SetName(metric.Label)
+			metr.SetExportable(metric.Exportable)
+		}
+
+		var service, wait, visits, ops matrix.Metric
+
+		if service = r.Matrix.GetMetric("service_time"); service == nil {
+			r.Logger.Error().Stack().Msg("metric [service_time] required to calculate workload missing")
+		}
+
+		if wait = r.Matrix.GetMetric("wait_time"); wait == nil {
+			r.Logger.Error().Stack().Msg("metric [wait-time] required to calculate workload missing")
+		}
+
+		if visits = r.Matrix.GetMetric("visits"); visits == nil {
+			r.Logger.Error().Stack().Msg("metric [visits] required to calculate workload missing")
+		}
+
+		if service == nil || wait == nil || visits == nil {
+			return nil, errors.New(errors.MISSING_PARAM, "workload metrics")
+		}
+
+		if ops = r.Matrix.GetMetric("ops"); ops == nil {
+			if ops, err = r.Matrix.NewMetricFloat64("ops"); err != nil {
+				return nil, err
+			}
+			r.perfProp.counterInfo["ops"] = &counter{
+				name:        "ops",
+				description: "",
+				counterType: r.perfProp.counterInfo[visits.GetName()].counterType,
+				unit:        r.perfProp.counterInfo[visits.GetName()].unit,
+				denominator: "",
+			}
+		}
+
+		service.SetExportable(false)
+		wait.SetExportable(false)
+		visits.SetExportable(false)
+
+		if resourceMap := r.Params.GetChildS("resource_map"); resourceMap == nil {
+			return nil, errors.New(errors.MISSING_PARAM, "resource_map")
+		} else {
+			for _, x := range resourceMap.GetChildren() {
+				name := x.GetNameS()
+				resource := x.GetContentS()
+
+				if m := r.Matrix.GetMetric(name); m != nil {
+					continue
+				}
+				if m, err := r.Matrix.NewMetricFloat64(name); err != nil {
+					return nil, err
+				} else {
+					r.perfProp.counterInfo[name] = &counter{
+						name:        "resource_latency",
+						description: "",
+						counterType: r.perfProp.counterInfo[service.GetName()].counterType,
+						unit:        r.perfProp.counterInfo[service.GetName()].unit,
+						denominator: "ops",
+					}
+					m.SetName("resource_latency")
+					m.SetLabel("resource", resource)
+
+					r.Logger.Debug().Str("name", name).Str("resource", resource).Msg("added workload latency metric")
+				}
+			}
+		}
+	}
+	return r.Matrix, nil
+}
+
 func (r *RestPerf) PollData() (*matrix.Matrix, error) {
 
 	var (
-		content      []byte
-		count        uint64
-		apiD, parseD time.Duration
-		startTime    time.Time
-		err          error
-		records      []interface{}
+		content         []byte
+		count           uint64
+		apiD, parseD    time.Duration
+		startTime       time.Time
+		err             error
+		records         []interface{}
+		instanceKeys    []string
+		resourceLatency matrix.Metric // for workload* objects
 	)
 
 	r.Logger.Debug().Msg("updating data cache")
@@ -367,6 +500,19 @@ func (r *RestPerf) PollData() (*matrix.Matrix, error) {
 
 	r.Logger.Debug().Str("object", r.Object).Str("records", numRecords.String()).Msg("Extracted records")
 
+	if isWorkloadDetailObject(r.Prop.Query) {
+		if resourceMap := r.Params.GetChildS("resource_map"); resourceMap == nil {
+			return nil, errors.New(errors.MISSING_PARAM, "resource_map")
+		} else {
+			instanceKeys = make([]string, 0)
+			for _, layer := range resourceMap.GetAllChildNamesS() {
+				for key := range r.Matrix.GetInstances() {
+					instanceKeys = append(instanceKeys, key+"."+layer)
+				}
+			}
+		}
+	}
+
 	results[1].ForEach(func(key, instanceData gjson.Result) bool {
 		var (
 			instanceKey string
@@ -389,21 +535,57 @@ func (r *RestPerf) PollData() (*matrix.Matrix, error) {
 			}
 		}
 
+		// special case for these two objects
+		// we need to process each latency layer for each instance/counter
+		if isWorkloadDetailObject(r.Prop.Query) {
+
+			layer := "" // latency layer (resource) for workloads
+
+			before, after, found := strings.Cut(instanceKey, ".")
+			if found {
+				instanceKey = before
+				layer = after
+			} else {
+				r.Logger.Warn().
+					Str("key", instanceKey).
+					Msg("Instance key has unexpected format")
+				return true
+			}
+
+			if resourceLatency = newData.GetMetric(layer); resourceLatency == nil {
+				r.Logger.Trace().
+					Str("layer", layer).
+					Msg("Resource-latency metric missing in cache")
+				return true
+			}
+		}
+
 		if r.Params.GetChildContentS("only_cluster_instance") != "true" {
 			if instanceKey == "" {
 				return true
 			}
 		}
 
-		if instance = newData.GetInstance(instanceKey); instance == nil {
-			r.Logger.Debug().
-				Str("key", instanceKey).
-				Msg("Skip instance key, not found in cache")
+		if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) {
+			instance = newData.GetInstance(strings.Split(instanceKey, ":")[1])
+		} else {
+			instance = newData.GetInstance(instanceKey)
+		}
+
+		if instance == nil {
+			if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) {
+				r.Logger.Debug().
+					Str("key", instanceKey).
+					Msg("Skip instance key, not found in cache")
+			} else {
+				r.Logger.Warn().
+					Str("key", instanceKey).
+					Msg("Skip instance key, not found in cache")
+			}
 			return true
 		}
 
 		//// add batch timestamp as custom counter
-
 		for label, display := range r.Prop.InstanceLabels {
 			value := parseProperties(instanceData, label)
 			if value.Exists() {
@@ -427,75 +609,100 @@ func (r *RestPerf) PollData() (*matrix.Matrix, error) {
 		for name, metric := range r.Prop.Metrics {
 			f := parseMetricResponse(instanceData, name)
 			if f.value != "" {
-				if f.isArray {
-					labels := strings.Split(f.label, ",")
-					values := strings.Split(f.value, ",")
-
-					if len(labels) != len(values) {
-						// warn & skip
-						r.Logger.Warn().
-							Stack().
-							Str("labels", f.label).
-							Str("value", f.value).
-							Msg("labels don't match parsed values")
-						continue
-					}
-
-					for i, label := range labels {
-						k := name + "#" + label
-						metr, ok := newData.GetMetrics()[k]
-						if !ok {
-							if metr, err = newData.NewMetricFloat64(k); err != nil {
-								r.Logger.Error().Err(err).
-									Str("name", k).
-									Msg("NewMetricFloat64")
-								continue
-							}
-							metr.SetName(metric.Label)
-							metr.SetLabel("metric", label)
-							// differentiate between array and normal counter
-							metr.SetArray(true)
-							metr.SetExportable(metric.Exportable)
-						}
-						if err = metr.SetValueString(instance, values[i]); err != nil {
+				// special case for workload_detail
+				if isWorkloadDetailObject(r.Prop.Query) {
+					if name == "wait_time" || name == "service_time" {
+						if err := resourceLatency.AddValueString(instance, f.value); err != nil {
 							r.Logger.Error().
 								Stack().
 								Err(err).
 								Str("name", name).
-								Str("label", label).
-								Str("value", values[i]).
-								Msg("Set value failed")
-							continue
+								Str("value", f.value).
+								Msg("Add resource-latency failed")
 						} else {
 							r.Logger.Trace().
 								Str("name", name).
-								Str("label", label).
-								Str("value", values[i]).
-								Msg("Set name.label = value")
+								Str("value", f.value).
+								Msg("Add resource-latency")
 							count++
 						}
+						continue
+					}
+					// "visits" are ignored. This counter is only used to set properties of ops counter
+					if name == "visits" {
+						continue
 					}
 				} else {
-					metr, ok := newData.GetMetrics()[name]
-					if !ok {
-						if metr, err = newData.NewMetricFloat64(name); err != nil {
-							r.Logger.Error().Err(err).
-								Str("name", name).
-								Msg("NewMetricFloat64")
+					if f.isArray {
+						labels := strings.Split(f.label, ",")
+						values := strings.Split(f.value, ",")
+
+						if len(labels) != len(values) {
+							// warn & skip
+							r.Logger.Warn().
+								Stack().
+								Str("labels", f.label).
+								Str("value", f.value).
+								Msg("labels don't match parsed values")
+							continue
 						}
-					}
-					metr.SetName(metric.Label)
-					metr.SetExportable(metric.Exportable)
-					if c, err := strconv.ParseFloat(f.value, 64); err == nil {
-						if err = metr.SetValueFloat64(instance, c); err != nil {
-							r.Logger.Error().Err(err).Str("key", metric.Name).Str("metric", metric.Label).
-								Msg("Unable to set float key on metric")
+
+						for i, label := range labels {
+							k := name + "#" + label
+							metr, ok := newData.GetMetrics()[k]
+							if !ok {
+								if metr, err = newData.NewMetricFloat64(k); err != nil {
+									r.Logger.Error().Err(err).
+										Str("name", k).
+										Msg("NewMetricFloat64")
+									continue
+								}
+								metr.SetName(metric.Label)
+								metr.SetLabel("metric", label)
+								// differentiate between array and normal counter
+								metr.SetArray(true)
+								metr.SetExportable(metric.Exportable)
+							}
+							if err = metr.SetValueString(instance, values[i]); err != nil {
+								r.Logger.Error().
+									Stack().
+									Err(err).
+									Str("name", name).
+									Str("label", label).
+									Str("value", values[i]).
+									Msg("Set value failed")
+								continue
+							} else {
+								r.Logger.Trace().
+									Str("name", name).
+									Str("label", label).
+									Str("value", values[i]).
+									Msg("Set name.label = value")
+								count++
+							}
 						}
 					} else {
-						r.Logger.Error().Err(err).Str("key", metric.Name).Str("metric", metric.Label).
-							Msg("Unable to parse float value")
+						metr, ok := newData.GetMetrics()[name]
+						if !ok {
+							if metr, err = newData.NewMetricFloat64(name); err != nil {
+								r.Logger.Error().Err(err).
+									Str("name", name).
+									Msg("NewMetricFloat64")
+							}
+						}
+						metr.SetName(metric.Label)
+						metr.SetExportable(metric.Exportable)
+						if c, err := strconv.ParseFloat(f.value, 64); err == nil {
+							if err = metr.SetValueFloat64(instance, c); err != nil {
+								r.Logger.Error().Err(err).Str("key", metric.Name).Str("metric", metric.Label).
+									Msg("Unable to set float key on metric")
+							}
+						} else {
+							r.Logger.Error().Err(err).Str("key", metric.Name).Str("metric", metric.Label).
+								Msg("Unable to parse float value")
+						}
+						count++
 					}
-					count++
 				}
 			} else {
 				r.Logger.Warn().Str("counter", name).Msg("Counter is nil. Unable to process. Check template")
@@ -513,6 +720,13 @@ func (r *RestPerf) PollData() (*matrix.Matrix, error) {
 		Str("parseTime", parseD.String()).
 		Msg("Collected")
 
+	if isWorkloadDetailObject(r.Prop.Query) {
+		if err := r.getParentOpsCounters(newData); err != nil {
+			// no point to continue as we can't calculate the other counters
+			return nil, err
+		}
+	}
+
 	_ = r.Metadata.LazySetValueInt64("api_time", "data", apiD.Microseconds())
 	_ = r.Metadata.LazySetValueInt64("parse_time", "data", parseD.Microseconds())
 	_ = r.Metadata.LazySetValueUint64("count", "data", count)
@@ -543,8 +757,10 @@ func (r *RestPerf) PollData() (*matrix.Matrix, error) {
 		if metric.GetName() != "timestamp" {
 			counter := r.counterLookup(metric, key)
 			if counter != nil {
-				// set metric unit
-				metric.SetLabel("unit", counter.unit)
+				if !isWorkloadDetailObject(r.Prop.Query) {
+					// set metric unit
+					metric.SetLabel("unit", counter.unit)
+				}
 				if counter.denominator == "" {
 					// does not require base counter
 					orderedNonDenominatorMetrics = append(orderedNonDenominatorMetrics, metric)
@@ -684,6 +900,112 @@ func (r *RestPerf) PollData() (*matrix.Matrix, error) {
 	return newData, nil
 }
 
+// Poll counter "ops" of the related/parent object, required for objects
+// workload_detail and workload_detail_volume. This counter is already
+// collected by the other collectors, so this poll is redundant
+// (until we implement some sort of inter-collector communication).
+func (r *RestPerf) getParentOpsCounters(data *matrix.Matrix) error {
+
+	var (
+		ops    matrix.Metric
+		object string
+		//instanceKeys []string
+		dataQuery string
+		err       error
+		records   []interface{}
+		content   []byte
+	)
+
+	if r.Prop.Query == qosDetailQuery {
+		dataQuery = path.Join(qosQuery, "rows")
+		object = "qos"
+	} else {
+		dataQuery = path.Join(qosVolumeQuery, "rows")
+		object = "qos_volume"
+	}
+
+	if ops = data.GetMetric("ops"); ops == nil {
+		r.Logger.Error().Stack().Err(nil).Msgf("ops counter not found in cache")
+		return errors.New(errors.MISSING_PARAM, "counter ops")
+	}
+
+	//instanceKeys = data.GetInstanceKeys()
+
+	var filter []string
+	filter = append(filter, "counters.name=ops")
+	href := rest.BuildHref(dataQuery, "*", filter, "", "", "", r.Prop.ReturnTimeOut, dataQuery)
+
+	r.Logger.Debug().Str("href", href).Msg("")
+	if href == "" {
+		return errors.New(errors.ERR_CONFIG, "empty url")
+	}
+
+	err = rest.FetchData(r.Client, href, &records)
+	if err != nil {
+		r.Logger.Error().Stack().Err(err).Str("href", href).Msg("Failed to fetch data")
+		return err
+	}
+
+	all := rest.Pagination{
+		Records:    records,
+		NumRecords: len(records),
+	}
+
+	content, err = json.Marshal(all)
+	if err != nil {
+		r.Logger.Error().Err(err).Str("ApiPath", dataQuery).Msg("Unable to marshal rest pagination")
+	}
+
+	if !gjson.ValidBytes(content) {
+		return fmt.Errorf("json is not valid for: %s", dataQuery)
+	}
+
+	results := gjson.GetManyBytes(content, "num_records", "records")
+	numRecords := results[0]
+	if numRecords.Int() == 0 {
+		return errors.New(errors.ERR_NO_INSTANCE, "no "+object+" instances on cluster")
+	}
+
+	r.Logger.Debug().Str("object", r.Object).Str("records", numRecords.String()).Msg("Extracted records")
+
+	results[1].ForEach(func(key, instanceData gjson.Result) bool {
+		var (
+			instanceKey string
+			instance    *matrix.Instance
+		)
+
+		if !instanceData.IsObject() {
+			r.Logger.Warn().Str("type", instanceData.Type.String()).Msg("Instance data is not object, skipping")
+			return true
+		}
+
+		value := parseProperties(instanceData, "name")
+		if value.Exists() {
+			instanceKey += value.String()
+		} else {
+			r.Logger.Warn().Str("key", "name").Msg("skip instance, missing key")
+			return true
+		}
+		instance = data.GetInstance(instanceKey)
+		if instance == nil {
+			r.Logger.Trace().Str("key", key.String()).Msg("skip instance not found in cache")
+			return true
+		}
+
+		counterName := "ops"
+		f := parseMetricResponse(instanceData, counterName)
+		if f.value != "" {
+			if err = ops.SetValueString(instance, f.value); err != nil {
+				r.Logger.Error().Stack().Err(err).Str("metric", counterName).Str("value", value.String()).Msg("set metric")
+			} else {
+				r.Logger.Trace().Msgf("+ metric (%s) = [%s%s%s]", counterName, color.Cyan, value, color.End)
+			}
+		}
+		return true
+	})
+	return nil
+}
+
 func (r *RestPerf) counterLookup(metric matrix.Metric, metricKey string) *counter {
 	var c *counter
 
@@ -723,8 +1045,27 @@ func (r *RestPerf) PollInstance() (*matrix.Matrix, error) {
 	oldSize = oldInstances.Size()
 
 	dataQuery := path.Join(r.Prop.Query, "rows")
+	instanceKeys := r.Prop.InstanceKeys
+	fields := "properties"
+	fields = "*"
+	var filter []string
+
+	if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) {
+		dataQuery = qosWorkloadQuery
+		if isWorkloadObject(r.Prop.Query) {
+			instanceKeys = []string{"uuid"}
+		}
+		if isWorkloadDetailObject(r.Prop.Query) {
+			instanceKeys = []string{"name"}
+		}
+		if r.Prop.Query == qosVolumeQuery || r.Prop.Query == qosDetailVolumeQuery {
+			filter = append(filter, "workload-class=autovolume")
+		} else {
+			filter = append(filter, "workload-class=user_defined")
+		}
+	}
 
-	href := rest.BuildHref(dataQuery, "properties", nil, "", "", "", r.Prop.ReturnTimeOut, dataQuery)
+	href := rest.BuildHref(dataQuery, fields, filter, "", "", "", r.Prop.ReturnTimeOut, dataQuery)
 
 	r.Logger.Debug().Str("href", href).Msg("")
 	if href == "" {
@@ -770,8 +1111,13 @@ func (r *RestPerf) PollInstance() (*matrix.Matrix, error) {
 		}
 
 		// extract instance key(s)
-		for _, k := range r.Prop.InstanceKeys {
-			value := parseProperties(instanceData, k)
+		for _, k := range instanceKeys {
+			var value gjson.Result
+			if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) {
+				value = instanceData.Get(k)
+			} else {
+				value = parseProperties(instanceData, k)
+			}
 			if value.Exists() {
 				instanceKey += value.String()
 			} else {
@@ -783,15 +1129,25 @@ func (r *RestPerf) PollInstance() (*matrix.Matrix, error) {
 		if oldInstances.Delete(instanceKey) {
 			// instance already in cache
 			r.Logger.Debug().Msgf("updated instance [%s%s%s%s]", color.Bold, color.Yellow, key, color.End)
-		} else if _, err := r.Matrix.NewInstance(instanceKey); err != nil {
+		} else if instance, err := r.Matrix.NewInstance(instanceKey); err != nil {
 			r.Logger.Error().Err(err).Str("Instance key", instanceKey).Msg("add instance")
 		} else {
 			r.Logger.Debug().
 				Str("key", instanceKey).
 				Msg("Added new instance")
+			if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) {
+				for label, display := range r.perfProp.qosLabels {
+					if value := instanceData.Get(label); value.Exists() {
+						instance.SetLabel(display, value.String())
+					} else {
+						r.Logger.Warn().Str("label", label).Str("instanceKey", instanceKey).Msgf("Missing label")
+
+					}
+				}
+				r.Logger.Debug().Str("query", r.Prop.Query).Str("key", key.String()).Str("qos labels", instance.GetLabels().String()).Msg("")
+			}
 		}
 		return true
-
 	})
 
 	for key := range oldInstances.Iter() {
@@ -812,6 +1168,16 @@ func (r *RestPerf) PollInstance() (*matrix.Matrix, error) {
 	return nil, err
 }
 
+func isWorkloadObject(query string) bool {
+	_, ok := qosQueries[query]
+	return ok
+}
+
+func isWorkloadDetailObject(query string) bool {
+	_, ok := qosDetailQueries[query]
+	return ok
+}
+
 // Interface guards
 var (
 	_ collector.Collector = (*RestPerf)(nil)
diff --git a/cmd/collectors/zapi/collector/zapi.go b/cmd/collectors/zapi/collector/zapi.go
index 276a20bb..d07d8a56 100644
--- a/cmd/collectors/zapi/collector/zapi.go
+++ b/cmd/collectors/zapi/collector/zapi.go
@@ -6,10 +6,13 @@ package zapi
 
 import (
 	"fmt"
+	"goharvest2/cmd/collectors/zapi/plugins/certificate"
 	"goharvest2/cmd/collectors/zapi/plugins/qtree"
+	"goharvest2/cmd/collectors/zapi/plugins/security"
 	"goharvest2/cmd/collectors/zapi/plugins/sensor"
 	"goharvest2/cmd/collectors/zapi/plugins/shelf"
 	"goharvest2/cmd/collectors/zapi/plugins/snapmirror"
+	"goharvest2/cmd/collectors/zapi/plugins/svm"
 	"goharvest2/cmd/collectors/zapi/plugins/volume"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/pkg/conf"
@@ -140,6 +143,12 @@ func (me *Zapi) LoadPlugin(kind string, abc *plugin.AbstractPlugin) plugin.Plugi
 		return volume.New(abc)
 	case "Sensor":
 		return sensor.New(abc)
+	case "Certificate":
+		return certificate.New(abc)
+	case "SVM":
+		return svm.New(abc)
+	case "Security":
+		return security.New(abc)
 	default:
 		me.Logger.Info().Msgf("no zapi plugin found for %s", kind)
 	}
diff --git a/cmd/collectors/zapi/plugins/certificate/certificate.go b/cmd/collectors/zapi/plugins/certificate/certificate.go
new file mode 100644
index 00000000..00b4e6a8
--- /dev/null
+++ b/cmd/collectors/zapi/plugins/certificate/certificate.go
@@ -0,0 +1,246 @@
+/*
+ * Copyright NetApp Inc, 2022 All rights reserved
+ */
+
+package certificate
+
+import (
+	"crypto/x509"
+	"encoding/pem"
+	"goharvest2/cmd/collectors"
+	"goharvest2/cmd/poller/plugin"
+	"goharvest2/pkg/api/ontapi/zapi"
+	"goharvest2/pkg/conf"
+	"goharvest2/pkg/dict"
+	"goharvest2/pkg/errors"
+	"goharvest2/pkg/matrix"
+	"goharvest2/pkg/tree/node"
+	"strconv"
+	"time"
+)
+
+const DefaultPluginDuration = 30 * time.Minute
+const DefaultDataPollDuration = 3 * time.Minute
+const BatchSize = "500"
+
+type Certificate struct {
+	*plugin.AbstractPlugin
+	data                 *matrix.Matrix
+	instanceKeys         map[string]string
+	instanceLabels       map[string]*dict.Dict
+	pluginInvocationRate int
+	currentVal           int
+	batchSize            string
+	client               *zapi.Client
+	query                string
+}
+
+func New(p *plugin.AbstractPlugin) plugin.Plugin {
+	return &Certificate{AbstractPlugin: p}
+}
+
+func (my *Certificate) Init() error {
+
+	var err error
+
+	if err = my.InitAbc(); err != nil {
+		return err
+	}
+
+	if my.client, err = zapi.New(conf.ZapiPoller(my.ParentParams)); err != nil {
+		my.Logger.Error().Stack().Err(err).Msg("connecting")
+		return err
+	}
+
+	if err = my.client.Init(5); err != nil {
+		return err
+	}
+
+	// Assigned the value to currentVal so that plugin would be invoked first time to populate cache.
+	if my.currentVal, err = collectors.SetPluginInterval(my.ParentParams, my.Params, my.Logger, DefaultDataPollDuration, DefaultPluginDuration); err != nil {
+		my.Logger.Error().Err(err).Stack().Msg("Failed while setting the plugin interval")
+		return err
+	}
+
+	if b := my.Params.GetChildContentS("batch_size"); b != "" {
+		if _, err := strconv.Atoi(b); err == nil {
+			my.batchSize = b
+			my.Logger.Info().Str("BatchSize", my.batchSize).Msg("using batch-size")
+		}
+	} else {
+		my.batchSize = BatchSize
+		my.Logger.Trace().Str("BatchSize", BatchSize).Msg("Using default batch-size")
+	}
+
+	return nil
+}
+
+func (my *Certificate) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
+
+	var (
+		adminVserver       string
+		adminVserverSerial string
+		err                error
+	)
+
+	if my.currentVal >= my.pluginInvocationRate {
+		my.currentVal = 0
+
+		// invoke vserver-get-iter zapi and get admin vserver name
+		if adminVserver, err = my.GetAdminVserver(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect admin vserver")
+			return nil, nil
+		}
+
+		// invoke security-ssl-get-iter zapi and get admin vserver's serial number
+		if adminVserverSerial, err = my.GetSecuritySsl(adminVserver); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect admin vserver's serial number")
+			return nil, nil
+		}
+
+		// update certificate instance based on admin vaserver serial
+		for _, certificateInstance := range data.GetInstances() {
+			if certificateInstance.IsExportable() {
+				certificateInstance.SetExportable(false)
+				serialNumber := certificateInstance.GetLabel("serial_number")
+
+				if serialNumber == adminVserverSerial {
+					certificateInstance.SetExportable(true)
+					my.setCertificateIssuerType(certificateInstance)
+					my.setCertificateValidity(data, certificateInstance)
+				}
+			}
+		}
+
+	}
+
+	my.currentVal++
+	return nil, nil
+}
+
+func (my *Certificate) setCertificateIssuerType(instance *matrix.Instance) {
+	var (
+		cert *x509.Certificate
+		err  error
+	)
+
+	certificatePEM := instance.GetLabel("certificatePEM")
+	certUuid := instance.GetLabel("uuid")
+
+	if certificatePEM == "" {
+		my.Logger.Warn().Str("uuid", certUuid).Msg("Certificate is not found")
+		instance.SetLabel("certificateIssuerType", "unknown")
+	} else {
+		instance.SetLabel("certificateIssuerType", "self_signed")
+		certDecoded, _ := pem.Decode([]byte(certificatePEM))
+		if certDecoded == nil {
+			my.Logger.Warn().Msg("PEM formatted object is not a X.509 certificate. Only PEM formatted X.509 certificate input is allowed")
+			instance.SetLabel("certificateIssuerType", "unknown")
+			return
+		}
+
+		if cert, err = x509.ParseCertificate(certDecoded.Bytes); err != nil {
+			my.Logger.Warn().Msg("PEM formatted object is not a X.509 certificate. Only PEM formatted X.509 certificate input is allowed")
+			instance.SetLabel("certificateIssuerType", "unknown")
+			return
+		}
+
+		// Verifies if certificate is self-issued. This is true if the subject and issuer are equal.
+		if cert.Subject.String() == cert.Issuer.String() {
+			// Verifies if certificate is self-signed. This is true if the certificate is signed using its own public key.
+			if err = cert.CheckSignature(x509.SHA256WithRSA, cert.RawTBSCertificate, cert.Signature); err != nil {
+				// Any verification exception means it is not signed with the give key. i.e. not self-signed
+				instance.SetLabel("certificateIssuerType", "ca_signed")
+			}
+		}
+	}
+}
+
+func (my *Certificate) setCertificateValidity(data *matrix.Matrix, instance *matrix.Instance) {
+	var (
+		expiryTimeMetric matrix.Metric
+	)
+
+	instance.SetLabel("certificateExpiryStatus", "unknown")
+
+	if expiryTimeMetric = data.GetMetric("certificate-info.expiration-date"); expiryTimeMetric == nil {
+		my.Logger.Error().Stack().Msg("missing expiry time metric")
+		return
+	}
+
+	if expiryTime, ok := expiryTimeMetric.GetValueFloat64(instance); ok {
+		// convert expiryTime from float64 to int64 and find difference
+		timestampDiff := time.Unix(int64(expiryTime), 0).Sub(time.Now()).Hours()
+
+		if timestampDiff <= 0 {
+			instance.SetLabel("certificateExpiryStatus", "expired")
+		} else {
+			// daysRemaining will be more than 0 if it has reached this point, convert to days
+			daysRemaining := timestampDiff / 24
+			if daysRemaining < 60 {
+				instance.SetLabel("certificateExpiryStatus", "expiring")
+			} else {
+				instance.SetLabel("certificateExpiryStatus", "active")
+			}
+		}
+	}
+
+}
+
+func (my *Certificate) GetAdminVserver() (string, error) {
+	var (
+		result       []*node.Node
+		request      *node.Node
+		err          error
+		adminVserver string
+	)
+
+	request = node.NewXmlS("vserver-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+	// Fetching only admin vserver
+	query := request.NewChildS("query", "")
+	vserverInfo := query.NewChildS("vserver-info", "")
+	vserverInfo.NewChildS("vserver-type", "admin")
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return "", err
+	}
+
+	if len(result) == 0 || result == nil {
+		return "", errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+	// This should be one iteration only as cluster can have one admin vserver
+	for _, svm := range result {
+		adminVserver = svm.GetChildContentS("vserver-name")
+	}
+	return adminVserver, nil
+}
+
+func (my *Certificate) GetSecuritySsl(adminSvm string) (string, error) {
+	var (
+		result            []*node.Node
+		request           *node.Node
+		err               error
+		certificateSerial string
+	)
+
+	request = node.NewXmlS("security-ssl-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+	// Fetching only admin vserver
+	query := request.NewChildS("query", "")
+	vserverInfo := query.NewChildS("vserver-ssl-info", "")
+	vserverInfo.NewChildS("vserver", adminSvm)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return "", err
+	}
+
+	if len(result) == 0 || result == nil {
+		return "", errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+	// This should be one iteration only as cluster can have one admin vserver
+	for _, ssl := range result {
+		certificateSerial = ssl.GetChildContentS("certificate-serial-number")
+	}
+	return certificateSerial, nil
+}
diff --git a/cmd/collectors/zapi/plugins/security/security.go b/cmd/collectors/zapi/plugins/security/security.go
new file mode 100644
index 00000000..be9043c7
--- /dev/null
+++ b/cmd/collectors/zapi/plugins/security/security.go
@@ -0,0 +1,170 @@
+/*
+ * Copyright NetApp Inc, 2022 All rights reserved
+ */
+package security
+
+import (
+	"goharvest2/cmd/collectors"
+	"goharvest2/cmd/poller/plugin"
+	"goharvest2/pkg/api/ontapi/zapi"
+	"goharvest2/pkg/conf"
+	"goharvest2/pkg/errors"
+	"goharvest2/pkg/matrix"
+	"goharvest2/pkg/tree/node"
+	"time"
+)
+
+const DefaultPluginDuration = 30 * time.Minute
+const DefaultDataPollDuration = 3 * time.Minute
+
+type Security struct {
+	*plugin.AbstractPlugin
+	pluginInvocationRate int
+	currentVal           int
+	batchSize            string
+	client               *zapi.Client
+	query                string
+	fipsEnabled          string
+	rsh_enabled          string
+	telnet_enabled       string
+}
+
+func New(p *plugin.AbstractPlugin) plugin.Plugin {
+	return &Security{AbstractPlugin: p}
+}
+
+func (my *Security) Init() error {
+
+	var err error
+
+	if err = my.InitAbc(); err != nil {
+		return err
+	}
+
+	if my.client, err = zapi.New(conf.ZapiPoller(my.ParentParams)); err != nil {
+		my.Logger.Error().Stack().Err(err).Msg("connecting")
+		return err
+	}
+
+	if err = my.client.Init(5); err != nil {
+		return err
+	}
+
+	// Assigned the value to currentVal so that plugin would be invoked first time to populate cache.
+	if my.currentVal, err = collectors.SetPluginInterval(my.ParentParams, my.Params, my.Logger, DefaultDataPollDuration, DefaultPluginDuration); err != nil {
+		my.Logger.Error().Err(err).Stack().Msg("Failed while setting the plugin interval")
+		return err
+	}
+
+	return nil
+}
+
+func (my *Security) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
+
+	var (
+		err error
+	)
+
+	if my.currentVal >= my.pluginInvocationRate {
+		my.currentVal = 0
+
+		// invoke security-config-get zapi with 'ssl' interface and get fips status
+		if my.fipsEnabled, err = my.getSecurityConfig(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect fips enable status")
+			//return nil, nil
+		}
+
+		// invoke security-protocol-get zapi with 'telnet' and 'rsh' and get
+		if my.telnet_enabled, my.rsh_enabled, err = my.getSecurityProtocols(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect telnet and rsh enable status")
+			//return nil, nil
+		}
+
+		// update instance based on the above zapi response
+		for _, securityInstance := range data.GetInstances() {
+			// Update fips_enabled label in instance
+			securityInstance.SetLabel("fips_enabled", my.fipsEnabled)
+
+			// Update telnet_enabled and rsh_enabled label in instance
+			securityInstance.SetLabel("telnet_enabled", my.telnet_enabled)
+			securityInstance.SetLabel("rsh_enabled", my.rsh_enabled)
+		}
+	}
+
+	my.currentVal++
+	return nil, nil
+}
+
+func (my *Security) getSecurityConfig() (string, error) {
+
+	var (
+		result      []*node.Node
+		request     *node.Node
+		fipsEnabled string
+		err         error
+	)
+
+	request = node.NewXmlS("security-config-get")
+	request.NewChildS("interface", "ssl")
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return "", err
+	}
+
+	if len(result) == 0 || result == nil {
+		return "", errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, securityConfig := range result {
+		fipsEnabled = securityConfig.GetChildContentS("is-fips-enabled")
+	}
+	return fipsEnabled, nil
+}
+
+func (my *Security) getSecurityProtocols() (string, string, error) {
+
+	var (
+		request       *node.Node
+		telnetEnabled string
+		rshEnabled    string
+		err           error
+	)
+
+	// Zapi call for telnet
+	request = node.NewXmlS("security-protocol-get")
+	request.NewChildS("application", "telnet")
+	if telnetEnabled, err = my.getEnabledValue(request); err != nil {
+		return "", "", err
+	}
+
+	// Zapi call for rsh
+	request = node.NewXmlS("security-protocol-get")
+	request.NewChildS("application", "rsh")
+	if rshEnabled, err = my.getEnabledValue(request); err != nil {
+		return "", "", err
+	}
+
+	return telnetEnabled, rshEnabled, nil
+}
+
+func (my *Security) getEnabledValue(request *node.Node) (string, error) {
+	var (
+		result  []*node.Node
+		enabled string
+		err     error
+	)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return "", err
+	}
+
+	if len(result) == 0 || result == nil {
+		return "", errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, securityConfig := range result {
+		enabled = securityConfig.GetChildContentS("enabled")
+	}
+
+	return enabled, nil
+}
diff --git a/cmd/collectors/zapi/plugins/snapmirror/snapmirror.go b/cmd/collectors/zapi/plugins/snapmirror/snapmirror.go
index 9290b2d4..a075a5dd 100644
--- a/cmd/collectors/zapi/plugins/snapmirror/snapmirror.go
+++ b/cmd/collectors/zapi/plugins/snapmirror/snapmirror.go
@@ -4,6 +4,7 @@
 package snapmirror
 
 import (
+	"goharvest2/cmd/collectors"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/pkg/api/ontapi/zapi"
 	"goharvest2/pkg/conf"
@@ -91,7 +92,7 @@ func (my *SnapMirror) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 			}
 
 			// update the protectedBy and protectionSourceType fields and derivedRelationshipType in snapmirror_labels
-			my.updateProtectedFields(instance)
+			collectors.UpdateProtectedFields(instance)
 		} else {
 			// 7 Mode
 			// source / destination nodes can be something like:
@@ -209,58 +210,3 @@ func (my *SnapMirror) updateLimitCache() error {
 	my.Logger.Debug().Msgf("updated limit cache for %d nodes", count)
 	return nil
 }
-
-func (my *SnapMirror) updateProtectedFields(instance *matrix.Instance) {
-
-	// check for group_type
-	if instance.GetLabel("group_type") != "" {
-		groupType := instance.GetLabel("group_type")
-		destinationVolume := instance.GetLabel("destination_volume")
-		sourceVolume := instance.GetLabel("source_volume")
-		destinationLocation := instance.GetLabel("destination_location")
-
-		isSvmDr := groupType == "vserver" && destinationVolume == "" && sourceVolume == ""
-		isCg := groupType == "CONSISTENCYGROUP" && strings.Contains(destinationLocation, ":/cg/")
-		isConstituentVolumeRelationshipWithinSvmDr := groupType == "vserver" && !strings.HasSuffix(destinationLocation, ":")
-		isConstituentVolumeRelationshipWithinCG := groupType == "CONSISTENCYGROUP" && !strings.Contains(destinationLocation, ":/cg/")
-
-		// Update protectedBy field
-		if isSvmDr || isConstituentVolumeRelationshipWithinSvmDr {
-			instance.SetLabel("protectedBy", "storage_vm")
-		} else if isCg || isConstituentVolumeRelationshipWithinCG {
-			instance.SetLabel("protectedBy", "cg")
-		} else {
-			instance.SetLabel("protectedBy", "volume")
-		}
-
-		// SVM-DR related information is populated
-		// Update protectionSourceType field
-		if isSvmDr {
-			instance.SetLabel("protectionSourceType", "storage_vm")
-		} else if isCg {
-			instance.SetLabel("protectionSourceType", "cg")
-		} else if isConstituentVolumeRelationshipWithinSvmDr || isConstituentVolumeRelationshipWithinCG || groupType == "none" || groupType == "flexgroup" {
-			instance.SetLabel("protectionSourceType", "volume")
-		} else {
-			instance.SetLabel("protectionSourceType", "not_mapped")
-		}
-	}
-
-	// Update derived_relationship_type field based on the policyType
-	relationshipType := instance.GetLabel("relationship_type")
-	if policyType := instance.GetLabel("policy_type"); policyType != "" {
-		if policyType == "strict_sync_mirror" {
-			instance.SetLabel("derived_relationship_type", "sync_mirror_strict")
-		} else if policyType == "sync_mirror" {
-			instance.SetLabel("derived_relationship_type", "sync_mirror")
-		} else if policyType == "mirror_vault" {
-			instance.SetLabel("derived_relationship_type", "mirror_vault")
-		} else if policyType == "automated_failover" {
-			instance.SetLabel("derived_relationship_type", "sync_mirror")
-		} else {
-			instance.SetLabel("derived_relationship_type", relationshipType)
-		}
-	} else {
-		instance.SetLabel("derived_relationship_type", relationshipType)
-	}
-}
diff --git a/cmd/collectors/zapi/plugins/svm/svm.go b/cmd/collectors/zapi/plugins/svm/svm.go
new file mode 100644
index 00000000..44184600
--- /dev/null
+++ b/cmd/collectors/zapi/plugins/svm/svm.go
@@ -0,0 +1,401 @@
+/*
+ * Copyright NetApp Inc, 2022 All rights reserved
+ */
+
+package svm
+
+import (
+	"goharvest2/cmd/collectors"
+	"goharvest2/cmd/poller/plugin"
+	"goharvest2/pkg/api/ontapi/zapi"
+	"goharvest2/pkg/conf"
+	"goharvest2/pkg/errors"
+	"goharvest2/pkg/matrix"
+	"goharvest2/pkg/tree/node"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const DefaultPluginDuration = 30 * time.Minute
+const DefaultDataPollDuration = 3 * time.Minute
+const BatchSize = "500"
+
+type SVM struct {
+	*plugin.AbstractPlugin
+	pluginInvocationRate int
+	currentVal           int
+	batchSize            string
+	client               *zapi.Client
+	auditProtocols       map[string]string
+	cifsProtocols        map[string]string
+	nsswitchInfo         map[string]nsswitch
+	nisInfo              map[string]string
+	cifsEnabled          map[string]bool
+	nfsEnabled           map[string]string
+	sshData              map[string]string
+}
+
+type nsswitch struct {
+	nsdb     []string
+	nssource []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
+	}
+
+	if my.client, err = zapi.New(conf.ZapiPoller(my.ParentParams)); err != nil {
+		my.Logger.Error().Stack().Err(err).Msg("connecting")
+		return err
+	}
+
+	if err = my.client.Init(5); err != nil {
+		return err
+	}
+
+	my.auditProtocols = make(map[string]string)
+	my.cifsProtocols = make(map[string]string)
+	my.nsswitchInfo = make(map[string]nsswitch)
+	my.nisInfo = make(map[string]string)
+	my.cifsEnabled = make(map[string]bool)
+	my.nfsEnabled = make(map[string]string)
+	my.sshData = make(map[string]string)
+
+	// Assigned the value to currentVal so that plugin would be invoked first time to populate cache.
+	if my.currentVal, err = collectors.SetPluginInterval(my.ParentParams, my.Params, my.Logger, DefaultDataPollDuration, DefaultPluginDuration); err != nil {
+		my.Logger.Error().Err(err).Stack().Msg("Failed while setting the plugin interval")
+		return err
+	}
+
+	if b := my.Params.GetChildContentS("batch_size"); b != "" {
+		if _, err := strconv.Atoi(b); err == nil {
+			my.batchSize = b
+			my.Logger.Info().Str("BatchSize", my.batchSize).Msg("using batch-size")
+		}
+	} else {
+		my.batchSize = BatchSize
+		my.Logger.Trace().Str("BatchSize", BatchSize).Msg("Using default batch-size")
+	}
+
+	return nil
+}
+
+func (my *SVM) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
+	var (
+		err error
+	)
+
+	if my.currentVal >= my.pluginInvocationRate {
+		my.currentVal = 0
+
+		// invoke fileservice-audit-config-get-iter zapi and get audit protocols
+		if my.auditProtocols, err = my.GetAuditProtocols(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect audit protocols")
+			//return nil, nil
+		}
+
+		// invoke cifs-security-get-iter zapi and get cifs protocols
+		if my.cifsProtocols, err = my.GetCifsProtocols(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect cifs protocols")
+			//return nil, nil
+		}
+
+		// invoke nameservice-nsswitch-get-iter zapi and get nsswitch info
+		if my.nsswitchInfo, err = my.GetNSSwitchInfo(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect nsswitch info")
+			//return nil, nil
+		}
+
+		// invoke nis-get-iter zapi and get nisdomain info
+		if my.nisInfo, err = my.GetNisInfo(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect nisdomain info")
+			//return nil, nil
+		}
+
+		// invoke cifs-server-get-iter zapi and get cifsenabled info
+		if my.cifsEnabled, err = my.GetCifsEnabled(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect cifsenabled info")
+			//return nil, nil
+		}
+
+		// invoke nfs-service-get-iter zapi and get cifsenabled info
+		if my.nfsEnabled, err = my.GetNfsEnabled(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect nfsenabled info")
+			//return nil, nil
+		}
+
+		// invoke security-ssh-get-iter zapi and get ssh data
+		if my.sshData, err = my.GetSshData(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect ssh data")
+			//return nil, nil
+		}
+
+		// 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 cifs_ntlm_enabled label in svm
+			if ntmlEnabled, ok := my.cifsProtocols[svmName]; ok {
+				svmInstance.SetLabel("cifs_ntlm_enabled", ntmlEnabled)
+			}
+
+			// 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 {
+				ns_db := strings.Join(nsswitchInfo.nsdb, ",")
+				ns_source := strings.Join(nsswitchInfo.nssource, ",")
+				nis_domain := my.nisInfo[svmName]
+				svmInstance.SetLabel("ns_source", ns_source)
+				svmInstance.SetLabel("ns_db", ns_db)
+				collectors.SetNameservice(ns_db, ns_source, nis_domain, svmInstance)
+			}
+
+			// Update cifs_protocol_enabled label in svm
+			if cifsEnable, ok := my.cifsEnabled[svmName]; ok {
+				svmInstance.SetLabel("cifs_protocol_enabled", strconv.FormatBool(cifsEnable))
+			}
+
+			// Update nfs_protocol_enabled label in svm
+			if nfsEnable, ok := my.nfsEnabled[svmName]; ok {
+				svmInstance.SetLabel("nfs_protocol_enabled", nfsEnable)
+			}
+
+			// Update ciphers label in svm
+			if sshInfo, ok := my.sshData[svmName]; ok {
+				svmInstance.SetLabel("ciphers", sshInfo)
+			}
+
+		}
+	}
+
+	my.currentVal++
+	return nil, nil
+}
+
+func (my *SVM) GetAuditProtocols() (map[string]string, error) {
+	var (
+		result                []*node.Node
+		request               *node.Node
+		vserverAuditEnableMap map[string]string
+		err                   error
+	)
+
+	vserverAuditEnableMap = make(map[string]string)
+
+	request = node.NewXmlS("fileservice-audit-config-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, fileServiceAuditConfig := range result {
+		auditEnabled := fileServiceAuditConfig.GetChildContentS("is-enabled")
+		svmName := fileServiceAuditConfig.GetChildContentS("vserver")
+		vserverAuditEnableMap[svmName] = auditEnabled
+	}
+	return vserverAuditEnableMap, nil
+}
+
+func (my *SVM) GetCifsProtocols() (map[string]string, error) {
+	var (
+		result               []*node.Node
+		request              *node.Node
+		vserverCifsEnableMap map[string]string
+		err                  error
+	)
+
+	vserverCifsEnableMap = make(map[string]string)
+
+	request = node.NewXmlS("cifs-security-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, cifsSecurity := range result {
+		lmCompatibilityLevel := cifsSecurity.GetChildContentS("lm-compatibility-level")
+		svmName := cifsSecurity.GetChildContentS("vserver")
+		vserverCifsEnableMap[svmName] = lmCompatibilityLevel
+	}
+	return vserverCifsEnableMap, nil
+}
+
+func (my *SVM) GetNSSwitchInfo() (map[string]nsswitch, error) {
+	var (
+		result             []*node.Node
+		request            *node.Node
+		vserverNsswitchMap map[string]nsswitch
+		ns                 nsswitch
+		ok                 bool
+		err                error
+	)
+
+	vserverNsswitchMap = make(map[string]nsswitch)
+
+	request = node.NewXmlS("nameservice-nsswitch-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, nsswitchConfig := range result {
+		nsdb := nsswitchConfig.GetChildContentS("nameservice-database")
+		svmName := nsswitchConfig.GetChildContentS("vserver-name")
+		nssource := nsswitchConfig.GetChildS("nameservice-sources")
+		nssourcelist := nssource.GetAllChildContentS()
+
+		if ns, ok = vserverNsswitchMap[svmName]; ok {
+			ns.nsdb = append(ns.nsdb, nsdb)
+			ns.nssource = append(ns.nssource, nssourcelist...)
+		} else {
+			ns = nsswitch{nsdb: []string{nsdb}, nssource: nssourcelist}
+		}
+		vserverNsswitchMap[svmName] = ns
+	}
+	return vserverNsswitchMap, nil
+}
+
+func (my *SVM) GetNisInfo() (map[string]string, error) {
+	var (
+		result        []*node.Node
+		request       *node.Node
+		vserverNisMap map[string]string
+		err           error
+	)
+
+	vserverNisMap = make(map[string]string)
+
+	request = node.NewXmlS("nis-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, nisData := range result {
+		nisDomain := nisData.GetChildContentS("nis-domain")
+		svmName := nisData.GetChildContentS("vserver")
+		vserverNisMap[svmName] = nisDomain
+	}
+	return vserverNisMap, nil
+}
+
+func (my *SVM) GetCifsEnabled() (map[string]bool, error) {
+	var (
+		result         []*node.Node
+		request        *node.Node
+		vserverCifsMap map[string]bool
+		err            error
+	)
+
+	vserverCifsMap = make(map[string]bool)
+
+	request = node.NewXmlS("cifs-server-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, cifsConfig := range result {
+		adminStatus := cifsConfig.GetChildContentS("administrative-status") == "up"
+		svmName := cifsConfig.GetChildContentS("vserver")
+		vserverCifsMap[svmName] = adminStatus
+	}
+	return vserverCifsMap, nil
+}
+
+func (my *SVM) GetNfsEnabled() (map[string]string, error) {
+	var (
+		result        []*node.Node
+		request       *node.Node
+		vserverNfsMap map[string]string
+		err           error
+	)
+
+	vserverNfsMap = make(map[string]string)
+
+	request = node.NewXmlS("nfs-service-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, nfsConfig := range result {
+		adminStatus := nfsConfig.GetChildContentS("is-nfs-access-enabled")
+		svmName := nfsConfig.GetChildContentS("vserver")
+		vserverNfsMap[svmName] = adminStatus
+	}
+	return vserverNfsMap, nil
+}
+
+func (my *SVM) GetSshData() (map[string]string, error) {
+	var (
+		result  []*node.Node
+		request *node.Node
+		sshMap  map[string]string
+		err     error
+	)
+
+	sshMap = make(map[string]string)
+
+	request = node.NewXmlS("security-ssh-get-iter")
+	request.NewChildS("max-records", my.batchSize)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, sshData := range result {
+		svmName := sshData.GetChildContentS("vserver-name")
+		sshList := sshData.GetChildS("ciphers").GetAllChildContentS()
+		sshMap[svmName] = strings.Join(sshList, ",")
+	}
+	return sshMap, nil
+}
diff --git a/cmd/collectors/zapi/plugins/volume/volume.go b/cmd/collectors/zapi/plugins/volume/volume.go
index f04d7b84..8b68ae78 100644
--- a/cmd/collectors/zapi/plugins/volume/volume.go
+++ b/cmd/collectors/zapi/plugins/volume/volume.go
@@ -1,25 +1,25 @@
 package volume
 
 import (
+	"goharvest2/cmd/collectors"
 	"goharvest2/cmd/poller/plugin"
 	"goharvest2/pkg/api/ontapi/zapi"
 	"goharvest2/pkg/conf"
-	"goharvest2/pkg/dict"
+	"goharvest2/pkg/errors"
 	"goharvest2/pkg/matrix"
 	"goharvest2/pkg/tree/node"
 	"strconv"
 	"strings"
+	"time"
 )
 
 const BatchSize = "500"
-const DefaultPluginInvocationRate = 10
-const DefaultDataPollDuration = 180
+const DefaultPluginDuration = 30 * time.Minute
+const DefaultDataPollDuration = 3 * time.Minute
 
 type Volume struct {
 	*plugin.AbstractPlugin
 	data                 *matrix.Matrix
-	instanceKeys         map[string]string
-	instanceLabels       map[string]*dict.Dict
 	batchSize            string
 	pluginInvocationRate int
 	currentVal           int
@@ -28,6 +28,12 @@ type Volume struct {
 	outgoingSM           map[string][]string
 	incomingSM           map[string]string
 	isHealthySM          map[string]bool
+	aggrsMap             map[string]string // aggregate-uuid -> aggregate-name map
+}
+
+type aggrData struct {
+	aggrUuid string
+	aggrName string
 }
 
 func New(p *plugin.AbstractPlugin) plugin.Plugin {
@@ -57,9 +63,10 @@ func (my *Volume) Init() error {
 	my.outgoingSM = make(map[string][]string)
 	my.incomingSM = make(map[string]string)
 	my.isHealthySM = make(map[string]bool)
+	my.aggrsMap = make(map[string]string)
 
 	// Assigned the value to currentVal so that plugin would be invoked first time to populate cache.
-	if my.currentVal, err = my.setPluginInterval(); err != nil {
+	if my.currentVal, err = collectors.SetPluginInterval(my.ParentParams, my.Params, my.Logger, DefaultDataPollDuration, DefaultPluginDuration); err != nil {
 		my.Logger.Error().Err(err).Stack().Msg("Failed while setting the plugin interval")
 	}
 
@@ -90,13 +97,26 @@ func (my *Volume) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 		my.currentVal = 0
 
 		// invoke snapmirror zapi and populate info in source and destination snapmirror maps
-		smSourceMap, smDestinationMap, err := my.GetSnapMirrors()
-		if err != nil {
-			my.Logger.Error().Stack().Err(err).Msg("Failed to collect snapmirror data")
+		if smSourceMap, smDestinationMap, err := my.GetSnapMirrors(); err != nil {
+			my.Logger.Warn().Stack().Err(err).Msg("Failed to collect snapmirror data")
+		} else {
+			// update internal cache based on volume and SM maps
+			my.updateMaps(data, smSourceMap, smDestinationMap)
 		}
 
-		// update internal cache based on volume and SM maps
-		my.updateMaps(data, smSourceMap, smDestinationMap)
+		// invoke disk-encrypt-get-iter zapi and populate disk info
+		disks, err1 := my.getDiskData()
+		// invoke aggr-status-get-iter zapi and populate aggr disk mapping info
+		aggrDiskMap, err2 := my.getAggrDiskMapping()
+
+		if err1 != nil {
+			my.Logger.Warn().Stack().Err(err1).Msg("Failed to collect disk data")
+		}
+		if err2 != nil {
+			my.Logger.Warn().Stack().Err(err2).Msg("Failed to collect aggregate-disk mapping data")
+		}
+		// update aggrsMap based on disk data and addr disk mapping
+		my.updateAggrMap(disks, aggrDiskMap)
 	}
 
 	// update volume instance labels
@@ -106,80 +126,12 @@ func (my *Volume) Run(data *matrix.Matrix) ([]*matrix.Matrix, error) {
 	return nil, nil
 }
 
-func (my *Volume) setPluginInterval() (int, error) {
-
-	volumeDataInterval := my.getDataInterval(my.ParentParams, DefaultDataPollDuration)
-	pluginDataInterval := my.getDataInterval(my.Params, DefaultPluginInvocationRate)
-	my.Logger.Debug().Int("VolumeDataInterval", volumeDataInterval).Int("PluginDataInterval", pluginDataInterval).Msg("Poll interval duration")
-	my.pluginInvocationRate = pluginDataInterval / volumeDataInterval
-
-	return my.pluginInvocationRate, nil
-}
-
-func (my *Volume) getDataInterval(param *node.Node, defaultInterval int) int {
-	var dataIntervalStr = ""
-	schedule := param.GetChildS("schedule")
-	if schedule != nil {
-		dataInterval := schedule.GetChildS("data")
-		if dataInterval != nil {
-			dataIntervalStr = dataInterval.GetContentS()
-		}
-	}
-
-	// Convert the interval from str to int
-	if dataIntervalStr != "" {
-		dataIntervalStr = strings.Split(dataIntervalStr, "s")[0]
-		if intervalVal, err := strconv.Atoi(dataIntervalStr); err == nil {
-			return intervalVal
-		}
-	}
-	return defaultInterval
-}
-
-func (my *Volume) updateProtectedFields(instance *matrix.Instance) {
-
-	// check for group_type
-	// Supported group_type are: "none", "vserver", "infinitevol", "consistencygroup", "flexgroup"
-	if instance.GetLabel("group_type") != "" {
-
-		groupType := instance.GetLabel("group_type")
-		destinationVolume := instance.GetLabel("destination_volume")
-		sourceVolume := instance.GetLabel("source_volume")
-		destinationLocation := instance.GetLabel("destination_location")
-
-		isSvmDr := groupType == "vserver" && destinationVolume == "" && sourceVolume == ""
-		isCg := groupType == "CONSISTENCYGROUP" && strings.Contains(destinationLocation, ":/cg/")
-		isConstituentVolumeRelationshipWithinSvmDr := groupType == "vserver" && !strings.HasSuffix(destinationLocation, ":")
-		isConstituentVolumeRelationshipWithinCG := groupType == "CONSISTENCYGROUP" && !strings.Contains(destinationLocation, ":/cg/")
-
-		// Update protectedBy label
-		if isSvmDr || isConstituentVolumeRelationshipWithinSvmDr {
-			instance.SetLabel("protectedBy", "storage_vm")
-		} else if isCg || isConstituentVolumeRelationshipWithinCG {
-			instance.SetLabel("protectedBy", "cg")
-		} else {
-			instance.SetLabel("protectedBy", "volume")
-		}
-
-		// SVM-DR related information is populated, Update protectionSourceType label
-		if isSvmDr {
-			instance.SetLabel("protectionSourceType", "storage_vm")
-		} else if isCg {
-			instance.SetLabel("protectionSourceType", "cg")
-		} else if isConstituentVolumeRelationshipWithinSvmDr || isConstituentVolumeRelationshipWithinCG || groupType == "none" || groupType == "flexgroup" {
-			instance.SetLabel("protectionSourceType", "volume")
-		} else {
-			instance.SetLabel("protectionSourceType", "not_mapped")
-		}
-	}
-}
-
 func (my *Volume) GetSnapMirrors() (map[string][]*matrix.Instance, map[string]*matrix.Instance, error) {
 	var (
-		request, result *node.Node
-		snapMirrors     []*node.Node
-		tag             string
-		err             error
+		request *node.Node
+		result  []*node.Node
+		tag     string
+		err     error
 	)
 
 	smSourceMap := make(map[string][]*matrix.Instance)
@@ -194,28 +146,15 @@ func (my *Volume) GetSnapMirrors() (map[string][]*matrix.Instance, map[string]*m
 	snapmirrorData := matrix.New(my.Parent+".SnapMirror", "sm", "sm")
 
 	for {
-		result, tag, err = my.client.InvokeBatchRequest(request, tag)
-
-		if err != nil {
+		if result, tag, err = collectors.InvokeZapiCall(my.client, request, my.Logger, tag); err != nil {
 			return nil, nil, err
 		}
 
-		if result == nil {
-			break
-		}
-
-		if x := result.GetChildS("attributes-list"); x != nil {
-			snapMirrors = x.GetChildren()
-		}
-
-		if len(snapMirrors) == 0 {
-			my.Logger.Info().Msg("no snapmirror instances found on system")
+		if len(result) == 0 || result == nil {
 			break
 		}
 
-		my.Logger.Debug().Int("snapmirrors", len(snapMirrors)).Msg("fetching snapmirrors")
-
-		for _, snapMirror := range snapMirrors {
+		for _, snapMirror := range result {
 			relationshipId := snapMirror.GetChildContentS("relationship-id")
 			groupType := snapMirror.GetChildContentS("relationship-group-type")
 			destinationVolume := snapMirror.GetChildContentS("destination-volume")
@@ -245,7 +184,7 @@ func (my *Volume) GetSnapMirrors() (map[string][]*matrix.Instance, map[string]*m
 			instance.SetLabel("destination_svm", destinationSvm)
 
 			// Update the protectedBy and protectionSourceType fields in snapmirror
-			my.updateProtectedFields(instance)
+			collectors.UpdateProtectedFields(instance)
 
 			// Update source snapmirror and destination snapmirror info in maps
 			if relationshipType == "data_protection" || relationshipType == "extended_data_protection" || relationshipType == "vault" {
@@ -315,6 +254,7 @@ func (my *Volume) updateVolumeLabels(data *matrix.Matrix) {
 		volumeName := volume.GetLabel("volume")
 		svmName := volume.GetLabel("svm")
 		volumeType := volume.GetLabel("type")
+		aggrUuid := volume.GetLabel("aggrUuid")
 		key := volumeName + "-" + svmName
 
 		// Update protectionRole label in volume
@@ -351,5 +291,79 @@ func (my *Volume) updateVolumeLabels(data *matrix.Matrix) {
 			volume.SetLabel("all_sm_healthy", strconv.FormatBool(healthy))
 		}
 
+		_, exist := my.aggrsMap[aggrUuid]
+		volume.SetLabel("isHardwareEncrypted", strconv.FormatBool(exist))
+	}
+}
+
+func (my *Volume) getDiskData() ([]string, error) {
+	var (
+		result    []*node.Node
+		diskNames []string
+		err       error
+	)
+
+	request := node.NewXmlS("disk-encrypt-get-iter")
+	//algorithm is -- Protection mode needs to be DATA or FULL
+	// Fetching rest of them and add as
+	query := request.NewChildS("query", "")
+	encryptInfoQuery := query.NewChildS("disk-encrypt-info", "")
+	encryptInfoQuery.NewChildS("protection-mode", "open|part|miss")
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, disk := range result {
+		diskName := disk.GetChildContentS("disk-name")
+		diskNames = append(diskNames, diskName)
+	}
+	return diskNames, nil
+}
+
+func (my *Volume) updateAggrMap(disks []string, aggrDiskMap map[string]aggrData) {
+	if disks != nil && aggrDiskMap != nil {
+		// Clean aggrsMap map
+		my.aggrsMap = make(map[string]string)
+
+		for _, disk := range disks {
+			aggr := aggrDiskMap[disk]
+			my.aggrsMap[aggr.aggrUuid] = aggr.aggrName
+		}
+	}
+}
+
+func (my *Volume) getAggrDiskMapping() (map[string]aggrData, error) {
+	var (
+		result        []*node.Node
+		aggrsDisksMap map[string]aggrData
+		diskName      string
+		err           error
+	)
+
+	request := node.NewXmlS("aggr-status-get-iter")
+	aggrsDisksMap = make(map[string]aggrData)
+
+	if result, _, err = collectors.InvokeZapiCall(my.client, request, my.Logger, ""); err != nil {
+		return nil, err
+	}
+
+	if len(result) == 0 || result == nil {
+		return nil, errors.New(errors.ERR_NO_INSTANCE, "no records found")
+	}
+
+	for _, aggrDiskData := range result {
+		aggrUuid := aggrDiskData.GetChildContentS("aaggregate-uuid")
+		aggrName := aggrDiskData.GetChildContentS("aggregate")
+		aggrDiskList := aggrDiskData.GetChildS("aggr-plex-list").GetChildS("aggr-plex-info").GetChildS("aggr-raidgroup-list").GetChildS("aggr-raidgroup-info").GetChildS("aggr-disk-list").GetChildren()
+		for _, aggrDisk := range aggrDiskList {
+			diskName = aggrDisk.GetChildContentS("disk")
+			aggrsDisksMap[diskName] = aggrData{aggrUuid: aggrUuid, aggrName: aggrName}
+		}
 	}
+	return aggrsDisksMap, nil
 }
diff --git a/conf/rest/9.12.0/clusterpeer.yaml b/conf/rest/9.12.0/clusterpeer.yaml
index a905b2d5..17e302d9 100644
--- a/conf/rest/9.12.0/clusterpeer.yaml
+++ b/conf/rest/9.12.0/clusterpeer.yaml
@@ -8,6 +8,12 @@ counters:
   - ^name                => name
   - ^encryption.state    => encryption_state
 
+plugins:
+  - LabelAgent:
+    # metric label zapi_value rest_value `default_value`
+    value_to_num:
+      - non_encrypted encryption_state none none `0`
+
 export_options:
   instance_keys:
     - uuid
diff --git a/conf/rest/9.12.0/security_certificate.yaml b/conf/rest/9.12.0/security_certificate.yaml
index 2d80c2b2..1b37230a 100644
--- a/conf/rest/9.12.0/security_certificate.yaml
+++ b/conf/rest/9.12.0/security_certificate.yaml
@@ -18,7 +18,6 @@ plugins:
       exclude_equals:
         - scope `svm`
       include_equals:
-#        - type `server` scope `cluster`   // TODO: To support multiple include with AND clause
         - type `server`
       value_to_num:
         - status name - - `0`
diff --git a/conf/rest/9.12.0/svm.yaml b/conf/rest/9.12.0/svm.yaml
index 0f5ecfa6..e6bf5621 100644
--- a/conf/rest/9.12.0/svm.yaml
+++ b/conf/rest/9.12.0/svm.yaml
@@ -87,4 +87,6 @@ export_options:
     - iscsi_authentication_type
     - iscsi_service_enabled
     - nis_authentication_enabled
+    - ns_source
+    - ns_db
 
diff --git a/conf/rest/9.12.0/volume.yaml b/conf/rest/9.12.0/volume.yaml
index 52d0fe15..794d503f 100644
--- a/conf/rest/9.12.0/volume.yaml
+++ b/conf/rest/9.12.0/volume.yaml
@@ -73,6 +73,20 @@ plugins:
         - style `flexgroup_constituent`
       replace:
         - style style `flexgroup_constituent` `flexgroup`
+      # To prevent visibility of transient volumes, uncomment the following lines
+#      exclude_regex:
+#        # Exclude SnapProtect/CommVault Intellisnap, Clone volumes have a “_CVclone” suffix
+#        - volume `.+_CVclone`
+#        # Exclude SnapCenter, Clone volumes have a “DDMMYYhhmmss” suffix
+#        - volume `.+(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d[0-9]{6}`
+#        # Exclude manually created SnapCreator clones, Clone volumes have a “cl_” prefix and a “_YYYYMMDDhhmmss” suffix
+#        - volume `cl_.+_(19|20)\d\d(0[1-9]|1[012])( 0[1-9]|[12][0-9]|3[01])[0-9]{6}`
+#        # Exclude SnapDrive/SnapManager, Clone volumes have a “sdw_cl_” prefix
+#        - volume `sdw_cl_.+`
+#        # Exclude Metadata volumes, CRS volumes in SVM-DR or MetroCluster have a “MDV_CRS_” prefix
+#        - volume `MDV_CRS_.+`
+#        # Exclude Metadata volumes, Audit volumes have a “MDV_aud_” prefix
+#        - volume `MDV_aud_.+`
   - Aggregator:
       - volume<style=flexgroup>volume node,svm,aggr,style
 
diff --git a/conf/rest/default.yaml b/conf/rest/default.yaml
index 164bb6d5..df6d5cfb 100644
--- a/conf/rest/default.yaml
+++ b/conf/rest/default.yaml
@@ -5,30 +5,27 @@ schedule:
   - data: 180s
 
 objects:
-  Aggr:             aggr.yaml
-  Disk:             disk.yaml
-  Lun:              lun.yaml
-  Node:             node.yaml
-  Port:             port.yaml
-  Qtree:            qtree.yaml
-  SVM:              svm.yaml
-  Sensor:           sensor.yaml
-  Shelf:            shelf.yaml
-  SnapMirror:       snapmirror.yaml
-  SnapshotPolicy:   snapshotPolicy.yaml
-  Status:           status.yaml
-  Subsystem:        subsystem.yaml
-  Volume:           volume.yaml
+  Aggr:                        aggr.yaml
+  ClusterPeer:                 clusterpeer.yaml
+  Disk:                        disk.yaml
+  Lun:                         lun.yaml
+  Node:                        node.yaml
+  NtpServer:                   ntpserver.yaml
+  Port:                        port.yaml
+  Qtree:                       qtree.yaml
+  Security:                    security.yaml
+  SecurityAccount:             security_account.yaml
+  SecurityAuditDestination:    security_audit_dest.yaml
+  SecurityCert:                security_certificate.yaml
+  SecurityLogin:               security_login.yaml
+  SecuritySsh:                 security_ssh.yaml
+  Sensor:                      sensor.yaml
+  Shelf:                       shelf.yaml
+  SnapMirror:                  snapmirror.yaml
+  SnapshotPolicy:              snapshotPolicy.yaml
+  Status:                      status.yaml
+  Subsystem:                   subsystem.yaml
+  Support:                     support.yaml
+  SVM:                         svm.yaml
+  Volume:                      volume.yaml
 
-
-
-# for security dashboard at cluster
-  ClusterPeer:              clusterpeer.yaml
-  NtpServer:                ntpserver.yaml
-  Security:                 security.yaml
-  SecuritySsh:              security_ssh.yaml
-  SecurityAccount:          security_account.yaml
-  SecurityAuditDestination: security_audit_dest.yaml
-  SecurityCert:             security_certificate.yaml
-  SecurityLogin:            security_login.yaml
-  Support:                  support.yaml
diff --git a/conf/restperf/9.12.0/cifs_node.yaml b/conf/restperf/9.12.0/cifs_node.yaml
index 17ff64f9..737874bf 100644
--- a/conf/restperf/9.12.0/cifs_node.yaml
+++ b/conf/restperf/9.12.0/cifs_node.yaml
@@ -5,7 +5,7 @@ object:                   node_cifs
 
 counters:
   - ^^id
-  - ^node.name                   => node
+  - ^node.name                    => node
   - op_count
   - total_ops                     => ops
   - total_read_ops                => read_ops
@@ -13,9 +13,9 @@ counters:
   - latency
   - average_read_latency          => read_latency
   - average_write_latency         => write_latency
-#  - connections
-#  - established_sessions
-#  - open_files
+  - connections
+  - established_sessions
+  - open_files
 
 export_options:
   instance_keys:
diff --git a/conf/restperf/9.12.0/cifs_svm.yaml b/conf/restperf/9.12.0/cifs_svm.yaml
index 47a801f1..0dd7bf0a 100644
--- a/conf/restperf/9.12.0/cifs_svm.yaml
+++ b/conf/restperf/9.12.0/cifs_svm.yaml
@@ -13,10 +13,10 @@ counters:
   - latency                  => latency
   - average_read_latency     => read_latency
   - average_write_latency    => write_latency
-  #- connections
-  #- established_sessions
-  #- open_files
-  #- signed_sessions
+  - connections
+  - established_sessions
+  - open_files
+  - signed_sessions
 
 export_options:
   instance_keys:
diff --git a/conf/restperf/9.12.0/disk.yaml b/conf/restperf/9.12.0/disk.yaml
new file mode 100644
index 00000000..6034fe32
--- /dev/null
+++ b/conf/restperf/9.12.0/disk.yaml
@@ -0,0 +1,57 @@
+name:                     Disk
+query:                    api/cluster/counter/tables/disk:constituent
+object:                   disk
+
+counters:
+  - ^^id
+  - ^name                => partition
+  - ^node.name           => node
+  - ^raid_group          => raid_group
+  - ^raid.type           => raid_type
+  - ^speed               => disk_speed
+#  - ^physical_disk_name    => disk  // hidden field
+  - cp_read_chain
+  - cp_read_latency
+  - cp_read_count        => cp_reads
+  - disk_busy_percent    => disk_busy
+  - capacity             => disk_capacity
+  - io_pending
+  - io_queued
+  - total_transfer_count
+  - user_read_chain
+  - user_read_block_count
+  - user_read_latency
+  - user_read_count
+  - user_write_chain
+  - user_write_block_count
+  - user_write_latency
+  - user_write_count
+
+plugins:
+  LabelAgent:
+    split:
+      - raid_group `/` ,aggr,plex,raid
+  Aggregator:
+  # plugin will create summary/average for each object
+  # any names after the object names will be treated as
+  # label names that will be added to instances
+    - node
+    - aggr ...
+  #  - plex node aggr
+  #  - raid node aggr plex
+
+# only export node/aggr aggregations from plugin
+# set this true or comment, to get data for each disk
+export_data: false
+
+export_options:
+  instance_keys:
+    - partition
+    - aggr
+    - node
+    - disk
+    - raid
+    - plex
+  instance_labels:
+    - disk_speed
+    - raid_type
diff --git a/conf/restperf/9.12.0/ext_cache_obj.yaml b/conf/restperf/9.12.0/ext_cache_obj.yaml
new file mode 100644
index 00000000..e10cfe65
--- /dev/null
+++ b/conf/restperf/9.12.0/ext_cache_obj.yaml
@@ -0,0 +1,31 @@
+name:                     ExtCacheObj
+query:                    api/cluster/counter/tables/external_cache
+object:                   flashcache
+
+counters:
+  - ^^id
+  - ^node.name               => node
+  - disk_reads_replaced
+  - accesses
+  - hit.percent              => hit_percent
+  - inserts
+  - evicts
+  - invalidates
+  - usage
+  - hit.total                => hit
+  - hit.normal_level_zero
+  - hit.metadata_file        => hit_metadata_file
+  - hit.directory            => hit_directory
+  - hit.indirect             => hit_indirect
+  - miss.total               => miss_total
+  - miss.normal_level_zero   => miss_normal_level_zero
+  - miss.metadata_file       => miss_metadata_file
+  - miss.directory           => miss_directory
+  - miss.indirect            => miss_indirect
+
+override:
+  - hit.percent: average
+
+export_options:
+  instance_keys:
+    - node
diff --git a/conf/restperf/9.12.0/fcp.yaml b/conf/restperf/9.12.0/fcp.yaml
index cc610a9e..cc7e060f 100644
--- a/conf/restperf/9.12.0/fcp.yaml
+++ b/conf/restperf/9.12.0/fcp.yaml
@@ -4,8 +4,9 @@ object:                   fcp
 
 counters:
   - ^^id
-  - name                        => port
-  - node.name                   => node
+  - ^name                               => port
+  - ^node.name                          => node
+  - ^link.speed                         => speed
   - average_other_latency
   - average_read_latency
   - average_write_latency
@@ -16,9 +17,8 @@ counters:
   - write_ops
   - other_ops
   - total_ops
-  - link.speed                  => speed
-  - link.down                   => link_down
-  - link.failure                => link_failure
+  - link.down                           => link_down
+  - link.failure                        => link_failure
   - loss_of_signal
   - loss_of_sync
   - primitive_seq_err
@@ -29,9 +29,34 @@ counters:
   - threshold_full
   - discarded_frames_count
   - interrupt_count
-  - invalid.transmission_word   => invalid_transmission_word
-  - isr.count                   => isr_count
-  - invalid.crc                 => invalid_crc
+  - invalid.transmission_word           => invalid_transmission_word
+  - isr.count                           => isr_count
+  - invalid.crc                         => invalid_crc
+  - nvmf.average_other_latency          => nvmf_average_other_latency
+  - nvmf.average_read_latency           => nvmf_average_read_latency
+  - nvmf.average_remote_other_latency   => nvmf_average_read_latency
+  - nvmf.average_remote_read_latency    => nvmf_average_read_latency
+  - nvmf.average_remote_write_latency   => nvmf_average_read_latency
+  - nvmf.average_write_latency          => nvmf_average_read_latency
+  - nvmf.caw_data                       => nvmf_caw_data
+  - nvmf.caw_ops                        => nvmf_caw_ops
+  - nvmf.command_slots                  => nvmf_command_slots
+  - nvmf.other_ops                      => nvmf_other_ops
+  - nvmf.read_data                      => nvmf_read_data
+  - nvmf.read_ops                       => nvmf_read_ops
+  - nvmf_remote.caw_data                => nvmf_remote_caw_data
+  - nvmf_remote.caw_ops                 => nvmf_remote_caw_ops
+  - nvmf_remote.other_ops               => nvmf_remote_other_ops
+  - nvmf_remote.read_data               => nvmf_remote_read_data
+  - nvmf_remote.read_ops                => nvmf_remote_read_ops
+  - nvmf_remote.total_data              => nvmf_remote_total_data
+  - nvmf.remote_total_ops               => nvmf_remote_total_ops    #revisit naming convention is not matching
+  - nvmf_remote.write_data              => nvmf_remote_write_data
+  - nvmf_remote.write_ops               => nvmf_remote_write_ops
+  - nvmf.total_data                     => nvmf_total_data
+  - nvmf.total_ops                      => nvmf_total_ops
+  - nvmf.write_data                     => nvmf_write_data
+  - nvmf.write_ops                      => nvmf_write_ops
 
 override:
   - link.speed: string
diff --git a/conf/restperf/9.12.0/iscsi_lif.yaml b/conf/restperf/9.12.0/iscsi_lif.yaml
new file mode 100644
index 00000000..947672e5
--- /dev/null
+++ b/conf/restperf/9.12.0/iscsi_lif.yaml
@@ -0,0 +1,29 @@
+name:                     ISCSI
+query:                    api/cluster/counter/tables/iscsi_lif
+object:                   iscsi_lif
+
+counters:
+  - ^^id
+  - ^name                  => lif
+  - ^svm.name              => svm
+  - ^node.name             => node
+  - protocol_errors
+  - read_data
+  - write_data
+  - iscsi_read_ops
+  - average_read_latency
+  - average_write_latency
+  - average_other_latency
+  - iscsi_write_ops
+  - iscsi_other_ops
+  - cmd_transferred
+  - average_latency
+
+override:
+  - cmd_transferred: rate
+
+export_options:
+  instance_keys:
+    - lif
+    - node
+    - svm
diff --git a/conf/restperf/9.12.0/lun.yaml b/conf/restperf/9.12.0/lun.yaml
new file mode 100644
index 00000000..17925825
--- /dev/null
+++ b/conf/restperf/9.12.0/lun.yaml
@@ -0,0 +1,47 @@
+name:                     Lun
+query:                    api/cluster/counter/tables/lun
+object:                   lun
+
+counters:
+  - ^^name
+  - ^svm.name                   => svm
+  - read_data
+  - write_data
+  - read_ops
+  - write_ops
+  - xcopy_requests
+  - writesame_requests
+  - writesame_unmap_requests
+  - caw_requests
+  - average_read_latency
+  - average_write_latency
+  - average_xcopy_latency
+  - unmap_requests
+  - writesame_unmap_requests
+  - enospc
+  - queue_full
+  - remote_bytes
+  - remote_ops
+  - read_partial_blocks
+  - write_partial_blocks
+  - write_align_histogram
+  - read_align_histogram
+
+override:
+  - writesame_requests: rate
+  - writesame_unmap_requests: rate
+  - caw_requests: rate
+  - unmap_requests: rate
+  - xcopy_requests: rate
+
+
+plugins:
+  LabelAgent:
+    split:
+      - lun `/` ,,volume,lun
+
+export_options:
+  instance_keys:
+    - lun # edited by plugin
+    - volume # added by plugin
+    - svm
diff --git a/conf/restperf/9.12.0/namespace.yaml b/conf/restperf/9.12.0/namespace.yaml
new file mode 100644
index 00000000..40cfe070
--- /dev/null
+++ b/conf/restperf/9.12.0/namespace.yaml
@@ -0,0 +1,34 @@
+name:                     Namespace
+query:                    api/cluster/counter/tables/namespace
+object:                   namespace
+
+counters:
+  - ^^id
+  - ^name
+  - ^svm.name                 => svm
+  - read_data
+  - write_data
+  - read_ops
+  - write_ops
+  - other_ops
+  - average_read_latency
+  - average_write_latency
+  - average_other_latency
+  - queue_full
+  - remote.read_data          => remote_read_data
+  - remote.read_ops           => remote_read_ops
+
+override:
+
+plugins:
+  LabelAgent:
+    split:
+      - name `/` ,,volume,namespace
+
+export_options:
+  instance_keys:
+    - svm
+    - volume
+    - namespace
+
+
diff --git a/conf/restperf/9.12.0/nfsv4.yaml b/conf/restperf/9.12.0/nfsv4.yaml
index 8b2ee4d5..264930a0 100644
--- a/conf/restperf/9.12.0/nfsv4.yaml
+++ b/conf/restperf/9.12.0/nfsv4.yaml
@@ -11,9 +11,9 @@ counters:
   - ^name                                 => svm
   - latency
   - total_ops                             => ops
-  - total.read_throughput	                => read_throughput
-  - total.throughput	                     => throughput
-  - total.write_throughput	               => write_throughput
+  - total.read_throughput                 => read_throughput
+  - total.throughput                      => throughput
+  - total.write_throughput                => write_throughput
   - access.total                          => access_total
   - close.total                           => close_total
   - commit.total                          => commit_total
diff --git a/conf/restperf/9.12.0/nfsv4_1.yaml b/conf/restperf/9.12.0/nfsv4_1.yaml
index eeff9966..7501ff87 100644
--- a/conf/restperf/9.12.0/nfsv4_1.yaml
+++ b/conf/restperf/9.12.0/nfsv4_1.yaml
@@ -11,9 +11,9 @@ counters:
   - ^name                                         => svm
   - latency
   - total_ops                                     => ops
-  - total.read_throughput	                        => read_throughput
-  - total.write_throughput	                       => throughput
-  - total.throughput	                             => write_throughput
+  - total.read_throughput                         => read_throughput
+  - total.write_throughput                        => throughput
+  - total.throughput                              => write_throughput
   - access.total                                  => access_total
   - backchannel_ctl.total                         => backchannel_ctl_total
   - bind_connections_to_session.total             => bind_connections_to_session_total
diff --git a/conf/restperf/9.12.0/nic_common.yaml b/conf/restperf/9.12.0/nic_common.yaml
new file mode 100644
index 00000000..f158b1ed
--- /dev/null
+++ b/conf/restperf/9.12.0/nic_common.yaml
@@ -0,0 +1,41 @@
+name:                     NicCommon
+query:                    api/cluster/counter/tables/nic_common
+object:                   nic
+
+counters:
+  - ^^id
+  - ^node.name              => node
+  - ^link_speed             => speed
+  - ^link_current_state     => state
+  - ^link_up_to_downs
+  - ^type
+  - receive_bytes
+  - transmit_bytes
+  - receive_alignment_errors
+  - receive_crc_errors
+  - receive_length_errors
+  - receive_total_errors
+  - receive_errors
+  - transmit_errors
+  - transmit_hw_errors
+  - transmit_total_errors
+
+override:
+  - link_speed: string
+
+plugins:
+#  - Nic
+  - LabelAgent:
+    # metric label zapi_value rest_value `default_value`
+    value_to_num:
+      - new_status state up up `0`
+
+export_options:
+  instance_keys:
+    - node
+    - nic
+  instance_labels:
+    - speed
+    - state
+    - type
+
diff --git a/conf/restperf/9.12.0/nvmf_lif.yaml b/conf/restperf/9.12.0/nvmf_lif.yaml
new file mode 100644
index 00000000..18e25725
--- /dev/null
+++ b/conf/restperf/9.12.0/nvmf_lif.yaml
@@ -0,0 +1,28 @@
+name:                     NVMfLif
+query:                    api/cluster/counter/tables/nvmf_lif
+object:                   nvme_lif
+
+counters:
+  - ^^id
+  - ^name                  => lif
+  - ^svm.name              => svm
+  - ^node.name             => node
+  - port_id                => port
+  - read_data
+  - read_ops
+  - average_read_latency
+  - average_write_latency
+  - average_other_latency
+  - write_data
+  - write_ops
+  - other_ops
+  - total_ops
+  - average_latency
+
+export_options:
+  instance_keys:
+    - lif
+    - svm
+    - node
+    - port
+
diff --git a/conf/restperf/9.12.0/resource_headroom_aggr.yaml b/conf/restperf/9.12.0/resource_headroom_aggr.yaml
index f8b5b190..8d4317fa 100644
--- a/conf/restperf/9.12.0/resource_headroom_aggr.yaml
+++ b/conf/restperf/9.12.0/resource_headroom_aggr.yaml
@@ -4,8 +4,8 @@ object:                   headroom_aggr
 
 counters:
   - ^^id
-  - ^name                            => instance_name
-  - ^node.name                       => node
+  - ^name                             => instance_name
+  - ^node.name                        => node
   - current_latency
   - current_ops
   - current_utilization
diff --git a/conf/restperf/9.12.0/system_node.yaml b/conf/restperf/9.12.0/system_node.yaml
new file mode 100644
index 00000000..40eb3243
--- /dev/null
+++ b/conf/restperf/9.12.0/system_node.yaml
@@ -0,0 +1,34 @@
+name:                     SystemNode
+query:                    api/cluster/counter/tables/system:node
+object:                   node
+
+counters:
+  - ^^id
+  - ^node.name                         => node
+  - average_processor_busy_percent     => avg_processor_busy
+  - cpu_elapsed_time
+  - memory
+  - total_data
+  - total_latency
+  - total_ops
+  - cifs_ops
+  - nfs_ops
+  - iscsi_ops
+  - fcp_ops
+  - nvme_fc_ops
+  - disk_data_read
+  - disk_data_written
+  - hdd_data_read
+  - hdd_data_written
+  - ssd_data_read
+  - ssd_data_written
+  - network_data_recieved
+  - network_data_sent
+  - fcp_data_recieved
+  - fcp_data_sent
+  - nvme_fc_data_recv
+  - nvme_fc_data_sent
+
+export_options:
+  instance_keys:
+    - node
diff --git a/conf/restperf/9.12.0/volume.yaml b/conf/restperf/9.12.0/volume.yaml
index 6db45ad3..76575462 100644
--- a/conf/restperf/9.12.0/volume.yaml
+++ b/conf/restperf/9.12.0/volume.yaml
@@ -22,6 +22,21 @@ counters:
 
 #plugins:
 #  - Volume
+#  - LabelAgent:
+#      # To prevent visibility of transient volumes, uncomment the following lines
+#      exclude_regex: [todo: need to test after Restperf infra completed]
+#        # Exclude SnapProtect/CommVault Intellisnap, Clone volumes have a “_CVclone” suffix
+#        - volume `.+_CVclone`
+#        # Exclude SnapCenter, Clone volumes have a “DDMMYYhhmmss” suffix
+#        - volume `.+(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d[0-9]{6}`
+#        # Exclude manually created SnapCreator clones, Clone volumes have a “cl_” prefix and a “_YYYYMMDDhhmmss” suffix
+#        - volume `cl_.+_(19|20)\d\d(0[1-9]|1[012])( 0[1-9]|[12][0-9]|3[01])[0-9]{6}`
+#        # Exclude SnapDrive/SnapManager, Clone volumes have a “sdw_cl_” prefix
+#        - volume `sdw_cl_.+`
+#        # Exclude Metadata volumes, CRS volumes in SVM-DR or MetroCluster have a “MDV_CRS_” prefix
+#        - volume `MDV_CRS_.+`
+#        # Exclude Metadata volumes, Audit volumes have a “MDV_aud_” prefix
+#        - volume `MDV_aud_.+`
 
 export_options:
   instance_keys:
diff --git a/conf/restperf/9.12.0/wafl.yaml b/conf/restperf/9.12.0/wafl.yaml
index 19871539..6f26439f 100644
--- a/conf/restperf/9.12.0/wafl.yaml
+++ b/conf/restperf/9.12.0/wafl.yaml
@@ -6,7 +6,7 @@ object:                   wafl
 #counter name doesn't exactly with zapiperf but these look better.
 counters:
   - ^^id
-  - ^node.name               => node
+  - ^node.name                         => node
   - average_non_wafl_msg_latency
   - average_msg_latency
   - average_replication_msg_latency
diff --git a/conf/restperf/9.12.0/wafl_comp_aggr_vol_bin.yaml b/conf/restperf/9.12.0/wafl_comp_aggr_vol_bin.yaml
new file mode 100644
index 00000000..9d927ce6
--- /dev/null
+++ b/conf/restperf/9.12.0/wafl_comp_aggr_vol_bin.yaml
@@ -0,0 +1,18 @@
+name:                     WAFLCompBin
+query:                    api/cluster/counter/tables/wafl_comp_aggr_vol_bin
+object:                   fabricpool
+
+counters:
+  - ^^id
+  - ^svm.name                    => svm
+  - ^volume.name                 => volume
+  - cloud_bin_operation
+  - cloud_bin_op_latency_average
+
+export_options:
+  instance_keys:
+    - svm
+    - volume
+
+override:
+  - cloud_bin_operation: delta
diff --git a/conf/restperf/9.12.0/wafl_hya_per_aggr.yaml b/conf/restperf/9.12.0/wafl_hya_per_aggr.yaml
new file mode 100644
index 00000000..d4495d18
--- /dev/null
+++ b/conf/restperf/9.12.0/wafl_hya_per_aggr.yaml
@@ -0,0 +1,32 @@
+name:                     WAFLAggr
+query:                    api/cluster/counter/tables/wafl_hya_per_aggregate
+object:                   flashpool
+
+counters:
+  - ^^id
+  - ^node.name                                      => node
+  - ssd_total
+  - ssd_total_used
+  - ssd_available
+  - ssd_read_cached
+  - ssd_write_cached
+  - read_ops_replaced
+  - read_ops_replaced_percent
+  - write_blocks_replaced
+  - write_blocks_replaced_percent
+  - hybrid_aggregate_read_hit_latency_average
+  - hybrid_aggregate_read_miss_latency_average
+  - hya_write_ssd_latency_average
+  - hybrid_aggregate_write_ssd_latency_average
+  - read_cache_ins_rate
+  - wc_write_blocks_total
+  - evict_remove_rate
+  - evict_destage_rate
+
+override:
+  - read_ops_replaced_percent: average
+  - write_blocks_replaced_percent: average
+
+export_options:
+  instance_keys:
+    - node
diff --git a/conf/restperf/9.12.0/wafl_hya_sizer.yaml b/conf/restperf/9.12.0/wafl_hya_sizer.yaml
new file mode 100644
index 00000000..d9523dda
--- /dev/null
+++ b/conf/restperf/9.12.0/wafl_hya_sizer.yaml
@@ -0,0 +1,12 @@
+name:                     WAFLSizer
+query:                    api/cluster/counter/tables/wafl_hya_sizer
+object:                   flashpool
+
+counters:
+  - ^^id
+  - ^node.name              => node
+  - cache_stats
+
+export_options:
+  instance_keys:
+    - node
diff --git a/conf/restperf/9.12.0/workload.yaml b/conf/restperf/9.12.0/workload.yaml
new file mode 100644
index 00000000..1eb28e40
--- /dev/null
+++ b/conf/restperf/9.12.0/workload.yaml
@@ -0,0 +1,51 @@
+# object Workload provides counters about workload usage
+name:                     Workload
+query:                    api/cluster/counter/tables/qos
+object:                   qos
+
+
+# recommended to use large interval, since workload objects are expensive
+client_timeout:           1m30s
+schedule:
+  - counter:  1200s
+  - instance: 600s
+  - data:     180s
+
+counters:
+  - ^^id
+  - ^name
+  - concurrency
+  - latency
+  - ops
+  - read_data
+  - read_io_type_percent      => read_io_type
+  - read_latency
+  - read_ops
+  - sequential_reads_percent  => sequential_reads
+  - sequential_writes_percent => sequential_writes
+  - total_data
+  - write_data
+  - write_latency
+  - write_ops
+
+override:
+  - read_io_type_base: delta
+
+qos_labels:
+  - svm.name                  => svm
+  - volume
+  - qtree
+  - lun
+  - file
+  - policy.name               => policy_group
+  - wid
+
+export_options:
+  instance_keys:
+    - wid
+    - svm
+    - volume
+    - qtree
+    - lun
+    - file
+    - policy_group
diff --git a/conf/restperf/9.12.0/workload_detail.yaml b/conf/restperf/9.12.0/workload_detail.yaml
new file mode 100644
index 00000000..c2402976
--- /dev/null
+++ b/conf/restperf/9.12.0/workload_detail.yaml
@@ -0,0 +1,69 @@
+
+# object provides latency breakdown per service or delay center
+
+name:                     WorkloadDetail
+query:                    api/cluster/counter/tables/qos_detail
+object:                   qos_detail
+
+instance_key:             name
+
+# recommended to use large interval, since workload objects are expensive
+client_timeout:           1m30s
+schedule:
+  - counter:  1200s
+  - instance: 600s
+  - data:     180s
+
+counters:
+  - ^^id
+  - ^resource.name  => resource
+  - ^node.name      => node
+  - service_time
+  - wait_time
+  - visits
+
+resource_map:
+  CPU_dblade: backend
+  CPU_nblade: frontend
+  DELAY_CENTER_CLOUD_IO: cloud
+  DELAY_CENTER_CLUSTER_INTERCONNECT: cluster
+  DELAY_CENTER_DISK_IO: disk
+  DELAY_CENTER_NETWORK: network
+  DELAY_CENTER_NVLOG_TRANSFER: nvlog
+  DELAY_CENTER_QOS_LIMIT: throttle
+  DELAY_CENTER_WAFL_SUSP_OTHER: suspend
+  # CPU_dblade_background :
+  # CPU_exempt :
+  # CPU_ha :
+  # CPU_idle :
+  # CPU_kahuna :
+  # CPU_network :
+  # CPU_protocol :
+  # CPU_raid :
+  # CPU_wafl_exempt :
+  # DELAY_CENTER_FLEXCACHE_RAL :
+  # DELAY_CENTER_FLEXCACHE_SPINHI :
+  # DELAY_CENTER_SYNC_REPL :
+  # DELAY_CENTER_WAFL_SUSP_CP :
+  # DISK_SSD_OTHER :
+
+qos_labels:
+  - name
+  - svm.name     => svm
+  - volume
+  - qtree
+  - lun
+  - file
+  - policy.name  => policy_group
+  - wid
+
+
+export_options:
+  instance_keys:
+    - wid
+    - svm
+    - volume
+    - qtree
+    - lun
+    - file
+    - policy_group
\ No newline at end of file
diff --git a/conf/restperf/9.12.0/workload_detail_volume.yaml b/conf/restperf/9.12.0/workload_detail_volume.yaml
new file mode 100644
index 00000000..f3d6d232
--- /dev/null
+++ b/conf/restperf/9.12.0/workload_detail_volume.yaml
@@ -0,0 +1,67 @@
+
+# object provides latency breakdown per service or delay center per volume
+name:                     WorkloadDetailVolume
+query:                    api/cluster/counter/tables/qos_detail_volume
+object:                   qos_detail_volume
+
+instance_key:             name
+
+# recommended to use large interval, since workload objects are expensive
+client_timeout:           1m30s
+schedule:
+  - counter: 1200s
+  - instance: 600s
+  - data: 180s
+
+counters:
+  - ^^id
+  - ^resource.name  => resource
+  - ^node.name      => node
+  - service_time
+  - wait_time
+  - visits
+
+resource_map:
+  CPU_dblade : backend
+  CPU_nblade : frontend
+  DELAY_CENTER_CLOUD_IO : cloud
+  DELAY_CENTER_CLUSTER_INTERCONNECT : cluster
+  DELAY_CENTER_DISK_IO : disk
+  DELAY_CENTER_NETWORK : network
+  DELAY_CENTER_NVLOG_TRANSFER : nvlog
+  DELAY_CENTER_QOS_LIMIT : throttle
+  DELAY_CENTER_WAFL_SUSP_OTHER : suspend
+  # CPU_dblade_background : 
+  # CPU_exempt : 
+  # CPU_ha : 
+  # CPU_idle : 
+  # CPU_kahuna : 
+  # CPU_network : 
+  # CPU_protocol : 
+  # CPU_raid : 
+  # CPU_wafl_exempt : 
+  # DELAY_CENTER_FLEXCACHE_RAL : 
+  # DELAY_CENTER_FLEXCACHE_SPINHI : 
+  # DELAY_CENTER_SYNC_REPL : 
+  # DELAY_CENTER_WAFL_SUSP_CP : 
+  # DISK_SSD_OTHER : 
+
+qos_labels:
+  - name
+  - svm.name      => svm
+  - volume
+  - qtree
+  - lun
+  - file
+  - policy.name   => policy_group
+  - wid
+
+export_options:
+  instance_keys:
+    - wid
+    - svm
+    - volume
+    - qtree
+    - lun
+    - file
+    - policy_group
diff --git a/conf/restperf/9.12.0/workload_volume.yaml b/conf/restperf/9.12.0/workload_volume.yaml
new file mode 100644
index 00000000..84b424f5
--- /dev/null
+++ b/conf/restperf/9.12.0/workload_volume.yaml
@@ -0,0 +1,52 @@
+
+# object provides counters per volume for workloads tracked via "autovol"
+# (i.e. not in a policy group)
+
+name:                     WorkloadVolume
+query:                    api/cluster/counter/tables/qos_volume
+object:                   qos_volume
+
+# recommended to use large interval, since workload objects are expensive
+client_timeout:           1m30s
+schedule:
+  - counter: 1200s
+  - instance: 600s
+  - data: 180s
+
+counters:
+  - ^^id
+  - latency
+  - ops
+  - read_data
+  - read_io_type_percent        => read_io_type
+  - read_latency
+  - read_ops
+  - sequential_reads_percent    => sequential_reads
+  - sequential_writes_percent   => sequential_writes
+  - total_data
+  - write_data
+  - write_latency
+  - write_ops
+
+
+override:
+  - read_io_type_base: delta
+
+qos_labels:
+  - svm.name                   => svm
+  - volume
+  - qtree
+  - lun
+  - file
+  - policy.name                => policy_group
+  - wid
+
+export_options:
+  instance_keys:
+    - wid
+    - svm
+    - volume
+    - qtree
+    - lun
+    - file
+    - policy_group
diff --git a/conf/restperf/default.yaml b/conf/restperf/default.yaml
index d6509b01..b17131c2 100644
--- a/conf/restperf/default.yaml
+++ b/conf/restperf/default.yaml
@@ -9,27 +9,44 @@ schedule:
 
 objects:
   CIFSNode:          cifs_node.yaml
-  Fcp:               fcp.yaml
+  Disk:              disk.yaml
+  ExtCacheObj:       ext_cache_obj.yaml
   FCVI:              fcvi.yaml
+  Fcp:               fcp.yaml
   HeadroomAggr:      resource_headroom_aggr.yaml
   HeadroomCPU:       resource_headroom_cpu.yaml
   HostAdapter:       hostadapter.yaml
   NFSv3Node:         nfsv3_node.yaml
   NFSv41Node:        nfsv4_1_node.yaml
   NFSv4Node:         nfsv4_node.yaml
+  NVMfLif:           nvmf_lif.yaml
+  Namespace:         namespace.yaml
+  NicCommon:         nic_common.yaml
   Path:              path.yaml
   Processor:         processor.yaml
   Qtree:             qtree.yaml
+  SystemNode:        system_node.yaml
   TokenManager:      token_manager.yaml
   VolumeNode:        volume_node.yaml
   WAFL:              wafl.yaml
+  WAFLAggr:          wafl_hya_per_aggr.yaml
+  WAFLSizer:         wafl_hya_sizer.yaml
 
   # SVM-level metrics
   CIFSsvm:           cifs_svm.yaml
   CopyManager:       copy_manager.yaml
   FcpLif:            fcp_lif.yaml
+  ISCSI:             iscsi_lif.yaml
   LIF:               lif.yaml
+  LUN:               lun.yaml
   NFSv3:             nfsv3.yaml
   NFSv41:            nfsv4_1.yaml
   NFSv4:             nfsv4.yaml
   Volume:            volume.yaml
+  WAFLCompBin:       wafl_comp_aggr_vol_bin.yaml
+
+  #  Uncomment to collect workload/QOS counters
+#  Workload:             workload.yaml
+#  WorkloadDetail:       workload_detail.yaml
+#  WorkloadVolume:       workload_volume.yaml
+#  WorkloadDetailVolume: workload_detail_volume.yaml
\ No newline at end of file
diff --git a/conf/zapi/7mode/8.6.0/volume.yaml b/conf/zapi/7mode/8.6.0/volume.yaml
index 1f37a556..5e14c072 100644
--- a/conf/zapi/7mode/8.6.0/volume.yaml
+++ b/conf/zapi/7mode/8.6.0/volume.yaml
@@ -35,6 +35,20 @@ plugins:
     # metric label zapi_value rest_value `default_value`
     value_to_num:
       - new_status state online online `0`
+    # To prevent visibility of transient volumes, uncomment the following lines
+#    exclude_regex:
+#      # Exclude SnapProtect/CommVault Intellisnap, Clone volumes have a “_CVclone” suffix
+#      - volume `.+_CVclone`
+#      # Exclude SnapCenter, Clone volumes have a “DDMMYYhhmmss” suffix
+#      - volume `.+(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d[0-9]{6}`
+#      # Exclude manually created SnapCreator clones, Clone volumes have a “cl_” prefix and a “_YYYYMMDDhhmmss” suffix
+#      - volume `cl_.+_(19|20)\d\d(0[1-9]|1[012])( 0[1-9]|[12][0-9]|3[01])[0-9]{6}`
+#      # Exclude SnapDrive/SnapManager, Clone volumes have a “sdw_cl_” prefix
+#      - volume `sdw_cl_.+`
+#      # Exclude Metadata volumes, CRS volumes in SVM-DR or MetroCluster have a “MDV_CRS_” prefix
+#      - volume `MDV_CRS_.+`
+#      # Exclude Metadata volumes, Audit volumes have a “MDV_aud_” prefix
+#      - volume `MDV_aud_.+`
 
 export_options:
   instance_keys:
diff --git a/conf/zapi/cdot/9.8.0/clusterpeer.yaml b/conf/zapi/cdot/9.8.0/clusterpeer.yaml
new file mode 100644
index 00000000..d7b57518
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/clusterpeer.yaml
@@ -0,0 +1,25 @@
+
+name:       ClusterPeer
+query:      cluster-peer-get-iter
+object:     cluster_peer
+
+counters:
+  cluster-peer-info:
+    - ^^cluster-uuid          => uuid
+    - ^cluster-name           => name
+    - ^encryption-protocol    => encryption_state
+
+collect_only_labels: true
+
+plugins:
+  - LabelAgent:
+    # metric label zapi_value rest_value `default_value`
+    value_to_num:
+      - non_encrypted encryption_state none none `0`
+
+export_options:
+  instance_keys:
+    - uuid
+  instance_labels:
+    - name
+    - encryption_state
\ No newline at end of file
diff --git a/conf/zapi/cdot/9.8.0/ntpserver.yaml b/conf/zapi/cdot/9.8.0/ntpserver.yaml
new file mode 100644
index 00000000..78eebca8
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/ntpserver.yaml
@@ -0,0 +1,17 @@
+
+name:       NtpServer
+query:      ntp-server-get-iter
+object:     ntpserver
+
+counters:
+  ntp-server-info:
+    - ^^server-name                => servers
+    - ^is-authentication-enabled   => authentication
+
+collect_only_labels: true
+
+export_options:
+  instance_keys:
+    - servers
+  instance_labels:
+    - authentication
\ No newline at end of file
diff --git a/conf/zapi/cdot/9.8.0/security.yaml b/conf/zapi/cdot/9.8.0/security.yaml
new file mode 100644
index 00000000..536461fe
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/security.yaml
@@ -0,0 +1,24 @@
+# This dummy api call is used for appending security related non-get iter response via plugin
+name:       Security
+query:      cluster-identity-get
+object:     security
+
+counters:
+  - ^^cluster-uuid             =>  uuid
+
+collect_only_labels: true
+only_cluster_instance: true
+no_max_records: true
+
+plugins:
+  - Security:
+      schedule:
+        - data: 180s  # should be multiple of data poll duration
+
+export_options:
+  instance_keys:
+    - uuid
+  instance_labels:
+    - fips_enabled
+    - telnet_enabled
+    - rsh_enabled
\ No newline at end of file
diff --git a/conf/zapi/cdot/9.8.0/security_account.yaml b/conf/zapi/cdot/9.8.0/security_account.yaml
new file mode 100644
index 00000000..defea169
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/security_account.yaml
@@ -0,0 +1,36 @@
+
+name:       SecurityAccount
+query:      security-login-get-iter
+object:     security_account
+
+counters:
+  security-login-account-info:
+    - ^^user-name                                 => user_name
+    - ^^application                               => applications
+    - ^^vserver                                   => svm
+    - ^^authentication-method                     => methods
+    - ^role-name                                  => role_name
+    - ^password-hash-algorithm                    => hash_algorithm
+    - ^is-locked                                  => locked
+
+collect_only_labels: true
+
+plugins:
+  - LabelAgent:
+      value_to_num_regex:
+        - samluser methods .*saml.*$ .*saml.*$ `0`
+        - ldapuser methods .*nsswitch.*$ .*nsswitch.*$ `0`
+        - certificateuser methods .*cert.*$ .*certificate.*$ `0`
+        - localuser methods .*password.*$ .*password.*$ `0`
+        - activediruser methods .*domain.*$ .*domain.*$ `0`
+
+export_options:
+  instance_keys:
+    - user_name
+    - applications
+    - svm
+    - methods
+  instance_labels:
+    - role_name
+    - hash_algorithm
+    - locked
\ No newline at end of file
diff --git a/conf/zapi/cdot/9.8.0/security_audit_dest.yaml b/conf/zapi/cdot/9.8.0/security_audit_dest.yaml
new file mode 100644
index 00000000..811667b2
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/security_audit_dest.yaml
@@ -0,0 +1,19 @@
+
+name:       SecurityAuditDestination
+query:      cluster-log-forward-get-iter
+object:     security_audit_destination
+
+counters:
+  cluster-log-forward-info:
+    - ^protocol                  => protocol
+    - port                       => port
+
+only_cluster_instance: true
+
+plugins:
+  - LabelAgent:
+      value_to_num:
+        - status protocol tcp_encrypted tcp_encrypted `0`
+
+export_options:
+  include_all_labels: true
\ No newline at end of file
diff --git a/conf/zapi/cdot/9.8.0/security_certificate.yaml b/conf/zapi/cdot/9.8.0/security_certificate.yaml
new file mode 100644
index 00000000..9c818b7a
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/security_certificate.yaml
@@ -0,0 +1,33 @@
+
+name:       SecurityCert
+query:      security-certificate-get-iter
+object:     security_certificate
+
+counters:
+  certificate-info:
+    - ^^cert-name              => name
+    - ^serial-number           => serial_number
+    - ^type                    => type
+    - ^vserver                 => svm
+    - ^public-certificate      => certificatePEM
+    - expiration-date          => expiry_time
+
+plugins:
+  - LabelAgent:
+      include_equals:
+        - type `server`
+      value_to_num:
+        - status name - - `0`
+  - Certificate:
+      schedule:
+        - data: 180s  # should be multiple of data poll duration
+
+export_options:
+  instance_keys:
+    - name
+  instance_labels:
+    - serial_number
+    - svm
+    - type
+    - certificateIssuerType
+    - certificateExpiryStatus
diff --git a/conf/zapi/cdot/9.8.0/security_login.yaml b/conf/zapi/cdot/9.8.0/security_login.yaml
new file mode 100644
index 00000000..b38ac063
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/security_login.yaml
@@ -0,0 +1,17 @@
+
+name:       SecurityLogin
+query:      vserver-login-banner-get-iter
+object:     security_login
+
+counters:
+  vserver-login-banner-info:
+    - ^^vserver      => svm
+    - ^message       => banner
+
+collect_only_labels: true
+
+export_options:
+  instance_keys:
+    - svm
+  instance_labels:
+    - banner
diff --git a/conf/zapi/cdot/9.8.0/support.yaml b/conf/zapi/cdot/9.8.0/support.yaml
new file mode 100644
index 00000000..6199295a
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/support.yaml
@@ -0,0 +1,23 @@
+
+name:       Support
+query:      autosupport-config-get-iter
+object:     support
+
+counters:
+  autosupport-config-info:
+    - ^^node-name                  => node
+    - ^is-enabled                  => asup_enabled
+    - ^transport                   => asup_https_configured
+    - ^is-private-data-removed     => asup_private_dataremoved
+
+collect_only_labels: true
+# at node level, As all the fields are same for both the nodes, we will only pick one node and ignore others
+only_cluster_instance: true
+
+export_options:
+  instance_keys:
+    - node
+  instance_labels:
+    - asup_enabled
+    - asup_https_configured
+    - asup_private_dataremoved
diff --git a/conf/zapi/cdot/9.8.0/svm.yaml b/conf/zapi/cdot/9.8.0/svm.yaml
new file mode 100644
index 00000000..fb14ddfb
--- /dev/null
+++ b/conf/zapi/cdot/9.8.0/svm.yaml
@@ -0,0 +1,41 @@
+
+name:       SVM
+query:      vserver-get-iter
+object:     svm
+
+counters:
+  vserver-info:
+    - ^^uuid                                  => svm_uuid
+    - ^vserver-name                           => svm
+    - ^aggr-list                              => aggr
+    - ^state                                  => state
+    - ^anti-ransomware-default-volume-state   => anti_ransomware_state
+    - name-server-switch:
+        - ^nsswitch                           => nameservice_switch
+
+collect_only_labels: true
+
+plugins:
+  - SVM:
+      schedule:
+        - data: 900s  # should be multiple of data poll duration
+  - LabelAgent:
+      value_to_num:
+        - new_status state online online `0`
+
+export_options:
+  instance_keys:
+    - svm
+    - aggr
+  instance_labels:
+    - state
+    - anti_ransomware_state
+    - nis_authentication_enabled
+    - audit_protocol_enabled
+    - cifs_ntlm_enabled
+    - cifs_protocol_enabled
+    - nfs_protocol_enabled
+    - nis_domain
+    - ns_source
+    - ns_db
+    - ciphers
diff --git a/conf/zapi/cdot/9.8.0/volume.yaml b/conf/zapi/cdot/9.8.0/volume.yaml
index e3803ee0..b5d0eab4 100644
--- a/conf/zapi/cdot/9.8.0/volume.yaml
+++ b/conf/zapi/cdot/9.8.0/volume.yaml
@@ -63,6 +63,7 @@ counters:
       - ^auto-snapshots-enabled             => auto_snapshots_enabled
       - ^snapshot-policy
       - snapshot-count
+    - ^encrypt                              => isEncrypted
 
 plugins:
   Volume:
@@ -75,6 +76,20 @@ plugins:
       - new_status state online online `0`
     exclude_equals:
       - style `flexgroup_constituent`
+    # To prevent visibility of transient volumes, uncomment the following lines
+#    exclude_regex:
+#      # Exclude SnapProtect/CommVault Intellisnap, Clone volumes have a “_CVclone” suffix
+#      - volume `.+_CVclone`
+#      # Exclude SnapCenter, Clone volumes have a “DDMMYYhhmmss” suffix
+#      - volume `.+(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d[0-9]{6}`
+#      # Exclude manually created SnapCreator clones, Clone volumes have a “cl_” prefix and a “_YYYYMMDDhhmmss” suffix
+#      - volume `cl_.+_(19|20)\d\d(0[1-9]|1[012])( 0[1-9]|[12][0-9]|3[01])[0-9]{6}`
+#      # Exclude SnapDrive/SnapManager, Clone volumes have a “sdw_cl_” prefix
+#      - volume `sdw_cl_.+`
+#      # Exclude Metadata volumes, CRS volumes in SVM-DR or MetroCluster have a “MDV_CRS_” prefix
+#      - volume `MDV_CRS_.+`
+#      # Exclude Metadata volumes, Audit volumes have a “MDV_aud_” prefix
+#      - volume `MDV_aud_.+`
     replace:
       - style style `flexgroup_constituent` `flexgroup`
   Aggregator:
@@ -96,4 +111,6 @@ export_options:
     - protectedBy
     - protectionRole
     - all_sm_healthy
+    - isEncrypted
+    - isHardwareEncrypted
 
diff --git a/conf/zapi/default.yaml b/conf/zapi/default.yaml
index a787aacc..0b588c44 100644
--- a/conf/zapi/default.yaml
+++ b/conf/zapi/default.yaml
@@ -7,17 +7,27 @@ schedule:
   - data: 180s
 
 objects:
-  Aggregate:           aggr.yaml
-  AggregateEfficiency: aggr_efficiency.yaml
-  Disk:                disk.yaml
-  Lun:                 lun.yaml
-  Node:                node.yaml
-  Qtree:               qtree.yaml
-  Sensor:              sensor.yaml
-  Shelf:               shelf.yaml
-  SnapMirror:          snapmirror.yaml
-  SnapshotPolicy:      snapshotPolicy.yaml
-  Status:              status.yaml
-  Status_7mode:        status_7.yaml
-  Subsystem:           subsystem.yaml
-  Volume:              volume.yaml
+  Aggregate:                   aggr.yaml
+  AggregateEfficiency:         aggr_efficiency.yaml
+  ClusterPeer:                 clusterpeer.yaml
+  Disk:                        disk.yaml
+  Lun:                         lun.yaml
+  Node:                        node.yaml
+  NtpServer:                   ntpserver.yaml
+  Qtree:                       qtree.yaml
+  Security:                    security.yaml
+  SecurityAccount:             security_account.yaml
+  SecurityAuditDestination:    security_audit_dest.yaml
+  SecurityCert:                security_certificate.yaml
+  SecurityLogin:               security_login.yaml
+  Sensor:                      sensor.yaml
+  Shelf:                       shelf.yaml
+  SnapMirror:                  snapmirror.yaml
+  SnapshotPolicy:              snapshotPolicy.yaml
+  Status:                      status.yaml
+  Status_7mode:                status_7.yaml
+  Subsystem:                   subsystem.yaml
+  Support:                     support.yaml
+  SVM:                         svm.yaml
+  Volume:                      volume.yaml
+
diff --git a/conf/zapiperf/7mode/8.2.5/volume.yaml b/conf/zapiperf/7mode/8.2.5/volume.yaml
index 9c4bc861..565a52c1 100644
--- a/conf/zapiperf/7mode/8.2.5/volume.yaml
+++ b/conf/zapiperf/7mode/8.2.5/volume.yaml
@@ -25,6 +25,21 @@ counters:
 
 plugins:
   - Volume
+#  - LabelAgent:
+#      # To prevent visibility of transient volumes, uncomment the following lines
+#      exclude_regex:
+#        # Exclude SnapProtect/CommVault Intellisnap, Clone volumes have a “_CVclone” suffix
+#        - volume `.+_CVclone`
+#        # Exclude SnapCenter, Clone volumes have a “DDMMYYhhmmss” suffix
+#        - volume `.+(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d[0-9]{6}`
+#        # Exclude manually created SnapCreator clones, Clone volumes have a “cl_” prefix and a “_YYYYMMDDhhmmss” suffix
+#        - volume `cl_.+_(19|20)\d\d(0[1-9]|1[012])( 0[1-9]|[12][0-9]|3[01])[0-9]{6}`
+#        # Exclude SnapDrive/SnapManager, Clone volumes have a “sdw_cl_” prefix
+#        - volume `sdw_cl_.+`
+#        # Exclude Metadata volumes, CRS volumes in SVM-DR or MetroCluster have a “MDV_CRS_” prefix
+#        - volume `MDV_CRS_.+`
+#        # Exclude Metadata volumes, Audit volumes have a “MDV_aud_” prefix
+#        - volume `MDV_aud_.+`
 
 export_options:
   instance_keys:
diff --git a/conf/zapiperf/cdot/9.8.0/volume.yaml b/conf/zapiperf/cdot/9.8.0/volume.yaml
index 9b2ea539..2e88c482 100644
--- a/conf/zapiperf/cdot/9.8.0/volume.yaml
+++ b/conf/zapiperf/cdot/9.8.0/volume.yaml
@@ -24,6 +24,21 @@ counters:
 
 plugins:
   - Volume
+#  - LabelAgent:
+#      # To prevent visibility of transient volumes, uncomment the following lines
+#      exclude_regex:
+#        # Exclude SnapProtect/CommVault Intellisnap, Clone volumes have a “_CVclone” suffix
+#        - volume `.+_CVclone`
+#        # Exclude SnapCenter, Clone volumes have a “DDMMYYhhmmss” suffix
+#        - volume `.+(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])\d\d[0-9]{6}`
+#        # Exclude manually created SnapCreator clones, Clone volumes have a “cl_” prefix and a “_YYYYMMDDhhmmss” suffix
+#        - volume `cl_.+_(19|20)\d\d(0[1-9]|1[012])( 0[1-9]|[12][0-9]|3[01])[0-9]{6}`
+#        # Exclude SnapDrive/SnapManager, Clone volumes have a “sdw_cl_” prefix
+#        - volume `sdw_cl_.+`
+#        # Exclude Metadata volumes, CRS volumes in SVM-DR or MetroCluster have a “MDV_CRS_” prefix
+#        - volume `MDV_CRS_.+`
+#        # Exclude Metadata volumes, Audit volumes have a “MDV_aud_” prefix
+#        - volume `MDV_aud_.+`
 
 export_options:
   instance_keys:
diff --git a/grafana/dashboards/cmode/harvest_dashboard_compliance.json b/grafana/dashboards/cmode/harvest_dashboard_compliance.json
index 80deb75e..23f4b04f 100644
--- a/grafana/dashboards/cmode/harvest_dashboard_compliance.json
+++ b/grafana/dashboards/cmode/harvest_dashboard_compliance.json
@@ -127,6 +127,35 @@
               {
                 "id": "max",
                 "value": 100
+              },
+              {
+                "id": "mappings",
+                "value": [
+                  {
+                    "options": {
+                      "-Infinity": {
+                        "index": 0,
+                        "text": "0%"
+                      },
+                      "Infinity": {
+                        "index": 1,
+                        "text": "0%"
+                      }
+                    },
+                    "type": "value"
+                  },
+                  {
+                    "options": {
+                      "from": -9999,
+                      "result": {
+                        "index": 2,
+                        "text": "0%"
+                      },
+                      "to": -1
+                    },
+                    "type": "range"
+                  }
+                ]
               }
             ]
           }
@@ -147,7 +176,7 @@
       "targets": [
         {
           "exemplar": false,
-          "expr": "count(group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"}))) or vector(0)",
+          "expr": "count(group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=\"$Cluster\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"}))) or vector(0)",
           "format": "time_series",
           "hide": false,
           "instant": true,
@@ -157,7 +186,7 @@
         },
         {
           "exemplar": false,
-          "expr": "count by (datacenter)(security_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\"}) or vector (1)",
+          "expr": "count by (datacenter)(security_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\"}) or vector (0)",
           "format": "time_series",
           "hide": false,
           "instant": true,
@@ -272,7 +301,32 @@
           },
           "unit": "short"
         },
-        "overrides": []
+        "overrides": [
+          {
+            "matcher": {
+              "id": "byName",
+              "options": "Compliant"
+            },
+            "properties": [
+              {
+                "id": "mappings",
+                "value": [
+                  {
+                    "options": {
+                      "from": -9999,
+                      "result": {
+                        "index": 0,
+                        "text": "0"
+                      },
+                      "to": -1
+                    },
+                    "type": "range"
+                  }
+                ]
+              }
+            ]
+          }
+        ]
       },
       "gridPos": {
         "h": 3,
@@ -301,7 +355,7 @@
       "targets": [
         {
           "exemplar": true,
-          "expr": "count by (datacenter) (security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"})",
+          "expr": "count by (datacenter) (security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) or vector(0)",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -312,7 +366,7 @@
         },
         {
           "exemplar": true,
-          "expr": "count(group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"}))) or vector(0)",
+          "expr": "count(group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=\"$Cluster\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"}))) or vector(0)",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -412,7 +466,7 @@
       "targets": [
         {
           "exemplar": true,
-          "expr": "count(group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"}))) or vector(0)",
+          "expr": "count(group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=\"$Cluster\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"}))) or vector(0)",
           "format": "time_series",
           "hide": false,
           "instant": false,
@@ -540,11 +594,6 @@
                         "color": "semi-dark-green",
                         "index": 1,
                         "text": "No"
-                      },
-                      "1": {
-                        "color": "semi-dark-orange",
-                        "index": 2,
-                        "text": "Yes"
                       }
                     },
                     "type": "value"
@@ -559,6 +608,18 @@
                       }
                     },
                     "type": "special"
+                  },
+                  {
+                    "options": {
+                      "from": 1,
+                      "result": {
+                        "color": "semi-dark-orange",
+                        "index": 2,
+                        "text": "Yes"
+                      },
+                      "to": 99999999
+                    },
+                    "type": "range"
                   }
                 ]
               },
@@ -1080,14 +1141,9 @@
                 "value": [
                   {
                     "options": {
-                      "none": {
-                        "color": "semi-dark-orange",
-                        "index": 1,
-                        "text": "Not Encrypted"
-                      },
-                      "tls_psk": {
+                      "0": {
                         "color": "semi-dark-green",
-                        "index": 2,
+                        "index": 1,
                         "text": "Encrypted"
                       }
                     },
@@ -1102,6 +1158,18 @@
                       }
                     },
                     "type": "special"
+                  },
+                  {
+                    "options": {
+                      "from": 1,
+                      "result": {
+                        "color": "semi-dark-orange",
+                        "index": 2,
+                        "text": "Not Encrypted"
+                      },
+                      "to": 9999999999
+                    },
+                    "type": "range"
                   }
                 ]
               },
@@ -1151,6 +1219,16 @@
                       }
                     },
                     "type": "value"
+                  },
+                  {
+                    "options": {
+                      "match": "null",
+                      "result": {
+                        "index": 4,
+                        "text": "Unknown"
+                      }
+                    },
+                    "type": "special"
                   }
                 ]
               },
@@ -1189,6 +1267,16 @@
                       }
                     },
                     "type": "value"
+                  },
+                  {
+                    "options": {
+                      "match": "null",
+                      "result": {
+                        "index": 3,
+                        "text": "Unknown"
+                      }
+                    },
+                    "type": "special"
                   }
                 ]
               },
@@ -1302,7 +1390,7 @@
         },
         {
           "exemplar": true,
-          "expr": "security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\",scope=\"cluster\"}",
+          "expr": "security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\",scope=\"cluster\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$Cluster\"}",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -1332,7 +1420,7 @@
         },
         {
           "exemplar": true,
-          "expr": "count by (datacenter, cluster, encryption_state) (cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state!=\"\"})",
+          "expr": "sum by (datacenter, cluster) (cluster_peer_non_encrypted{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"})",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -1402,7 +1490,7 @@
         },
         {
           "exemplar": true,
-          "expr": "group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"}))",
+          "expr": "group by (datacenter, cluster)(support_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", asup_enabled=\"true\", asup_https_configured!=\"https\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", telnet_enabled=\"true\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", rsh_enabled=\"true\"} or group by (datacenter, cluster)(security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", hash_algorithm=\"md5\"}) > 0 or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"\"} or cluster_peer_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", encryption_state=\"none\"} or group by (datacenter, cluster) (security_account_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", locked=\"false\"}) > 0 or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"cluster\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$Cluster\"} or count by (datacenter, cluster) (ntpserver_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\"}) < 1 or security_audit_destination_status{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", protocol!=\"tcp_encrypted\"} or security_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", fips_enabled=\"false\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", type=\"admin\", ciphers=~\".*_cbc.*\"} or group by (datacenter, cluster) ((svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", audit_protocol_enabled=\"false\"}) or security_ssh_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", scope=\"svm\", banner=\"\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"}))",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -1428,7 +1516,6 @@
                 "secured",
                 "banner",
                 "Value #G",
-                "encryption_state",
                 "Value #K",
                 "Value #I",
                 "Value #L",
@@ -1436,7 +1523,8 @@
                 "Value #N",
                 "certificateExpiryStatus",
                 "certificateIssuerType",
-                "Value #P"
+                "Value #P",
+                "Value #J"
               ]
             }
           }
@@ -1476,6 +1564,7 @@
             "indexByName": {
               "Value #P": 0,
               "Value #D": 11,
+              "Value #J": 12,
               "Value #G": 7,
               "Value #I": 13,
               "Value #K": 17,
@@ -1487,7 +1576,6 @@
               "certificateExpiryStatus": 2,
               "certificateIssuerType": 18,
               "cluster": 1,
-              "encryption_state": 12,
               "fips_enabled": 3,
               "locked": 9,
               "rsh_enabled": 10,
@@ -1502,10 +1590,12 @@
               "Value #F": "Login Banner",
               "Value #G": "Network Time Protocol",
               "Value #I": "Saml Users",
+              "Value #J": "Cluster Peering",
               "Value #K": "Local Users",
               "Value #L": "Active Directory Users",
               "Value #M": "Ldap Users",
               "Value #N": "Certificate Users",
+              "Value #P": "Compliant",
               "activediruser": "Active Directory Users",
               "asupEnabled": "",
               "asupHttpsConfigured": "",
@@ -1526,8 +1616,7 @@
               "rsh_enabled": "Remote Shell",
               "samluser": "Saml Users",
               "secured": "Insecure SSH Settings",
-              "telnet_enabled": "Telnet",
-              "Value #P": "Compliant"
+              "telnet_enabled": "Telnet"
             }
           }
         }
@@ -1612,7 +1701,7 @@
       "targets": [
         {
           "exemplar": false,
-          "expr": "count(group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"})) or vector(0)",
+          "expr": "count(group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"} or (svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"} unless on (svm) security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm!=\"$Cluster\", svm=~\"$SVM\"}))) or vector(0)",
           "format": "time_series",
           "hide": false,
           "instant": true,
@@ -1777,7 +1866,7 @@
         },
         {
           "exemplar": true,
-          "expr": "count(group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"})) or vector(0)",
+          "expr": "count(group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"} or (svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"} unless on (svm) security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm!=\"$Cluster\", svm=~\"$SVM\"}))) or vector(0)",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -1874,7 +1963,7 @@
       "targets": [
         {
           "exemplar": true,
-          "expr": "count(group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"}))",
+          "expr": "count(group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"} or (svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"} unless on (svm) security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm!=\"$Cluster\", svm=~\"$SVM\"})))",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -1975,10 +2064,6 @@
                   }
                 ]
               },
-              {
-                "id": "custom.width",
-                "value": 115
-              },
               {
                 "id": "custom.filterable",
                 "value": true
@@ -2021,10 +2106,6 @@
                   }
                 ]
               },
-              {
-                "id": "custom.width",
-                "value": 169
-              },
               {
                 "id": "custom.filterable",
                 "value": true
@@ -2151,10 +2232,6 @@
                   }
                 ]
               },
-              {
-                "id": "custom.width",
-                "value": 132
-              },
               {
                 "id": "custom.filterable",
                 "value": true
@@ -2380,6 +2457,16 @@
                       }
                     },
                     "type": "value"
+                  },
+                  {
+                    "options": {
+                      "match": "empty",
+                      "result": {
+                        "index": 2,
+                        "text": "N/A"
+                      }
+                    },
+                    "type": "special"
                   }
                 ]
               },
@@ -2500,7 +2587,7 @@
         },
         {
           "exemplar": true,
-          "expr": "security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", scope=\"svm\", svm=~\"$SVM\"}",
+          "expr": "security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", scope=\"svm\", svm=~\"$SVM\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm!=\"$Cluster\", svm=~\"$SVM\"}",
           "format": "table",
           "hide": false,
           "instant": true,
@@ -2540,7 +2627,7 @@
         },
         {
           "exemplar": true,
-          "expr": "group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"})",
+          "expr": "group by (datacenter, cluster, svm) ((svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", cifs_protocol_enabled=\"true\"} or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", nfs_protocol_enabled=\"true\"} and svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", audit_protocol_enabled=\"false\"}) or svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", ciphers=~\".*_cbc.*\"} or security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\", scope=\"svm\", banner=\"\"} or (svm_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm=~\"$SVM\"} unless on (svm) security_login_labels{datacenter=\"$Datacenter\", cluster=~\"$Cluster\", svm!=\"$Cluster\", svm=~\"$SVM\"}))",
           "format": "table",
           "hide": false,
           "instant": true,
diff --git a/grafana/dashboards/cmode/harvest_dashboard_security.json b/grafana/dashboards/cmode/harvest_dashboard_security.json
index ad1033d6..e358bc42 100644
--- a/grafana/dashboards/cmode/harvest_dashboard_security.json
+++ b/grafana/dashboards/cmode/harvest_dashboard_security.json
@@ -774,7 +774,7 @@
       "targets": [
         {
           "exemplar": true,
-          "expr": "count(volume_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", svm=~\"$SVM\"}) or vector (0)",
+          "expr": "count(volume_labels{datacenter=\"$Datacenter\",cluster=~\"$Cluster\", svm=~\"$SVM\", isEncrypted=\"false\", isHardwareEncrypted=\"false\"}) or vector (0)",
           "format": "time_series",
           "hide": false,
           "instant": true,
@@ -1450,6 +1450,7 @@
     },
     {
       "datasource": "Prometheus",
+      "description": "This panel requires a cluster with ONTAP 9.10+",
       "fieldConfig": {
         "defaults": {
           "color": {
@@ -1866,6 +1867,7 @@
     },
     {
       "datasource": "Prometheus",
+      "description": "This panel requires a cluster with ONTAP 9.10+",
       "fieldConfig": {
         "defaults": {
           "color": {


Test patch:
diff --git a/cmd/collectors/rest/plugins/util_test.go b/cmd/collectors/commonutils_test.go
similarity index 99%
rename from cmd/collectors/rest/plugins/util_test.go
rename to cmd/collectors/commonutils_test.go
index d5f17f3e..bf8fb8bb 100644
--- a/cmd/collectors/rest/plugins/util_test.go
+++ b/cmd/collectors/commonutils_test.go
@@ -1,4 +1,4 @@
-package plugins
+package collectors
 
 import (
 	"goharvest2/pkg/matrix"
diff --git a/cmd/collectors/zapi/plugins/snapmirror/snapmirror_test.go b/cmd/collectors/zapi/plugins/snapmirror/snapmirror_test.go
index 605e79a9..59198d09 100644
--- a/cmd/collectors/zapi/plugins/snapmirror/snapmirror_test.go
+++ b/cmd/collectors/zapi/plugins/snapmirror/snapmirror_test.go
@@ -1,12 +1,11 @@
 package snapmirror
 
 import (
+	"goharvest2/cmd/collectors"
 	"goharvest2/pkg/matrix"
 	"testing"
 )
 
-var sm *SnapMirror
-
 func TestProtectedFields(t *testing.T) {
 	instance := matrix.NewInstance(0)
 
@@ -33,7 +32,7 @@ func TestProtectedFields(t *testing.T) {
 // Test cases for protectedBy and protectionSourceType
 func testWithoutGroupType(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("group_type", "")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "" && instance.GetLabel("protectionSourceType") == "" {
 		// OK
@@ -46,7 +45,7 @@ func testSvmdr(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("group_type", "vserver")
 	instance.SetLabel("destination_volume", "")
 	instance.SetLabel("source_volume", "")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "storage_vm" && instance.GetLabel("protectionSourceType") == "storage_vm" {
 		// OK
@@ -60,7 +59,7 @@ func testConstituentVolumeWithinSvmdr(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("destination_volume", "destvol")
 	instance.SetLabel("source_volume", "sourcevol")
 	instance.SetLabel("destination_location", "test1")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "storage_vm" && instance.GetLabel("protectionSourceType") == "volume" {
 		// OK
@@ -72,7 +71,7 @@ func testConstituentVolumeWithinSvmdr(instance *matrix.Instance, t *testing.T) {
 func testCg(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("group_type", "CONSISTENCYGROUP")
 	instance.SetLabel("destination_location", "test123:/cg/")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "cg" && instance.GetLabel("protectionSourceType") == "cg" {
 		// OK
@@ -84,7 +83,7 @@ func testCg(instance *matrix.Instance, t *testing.T) {
 func testConstituentVolumeWithinCg(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("group_type", "CONSISTENCYGROUP")
 	instance.SetLabel("destination_location", "test123")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "cg" && instance.GetLabel("protectionSourceType") == "volume" {
 		// OK
@@ -95,7 +94,7 @@ func testConstituentVolumeWithinCg(instance *matrix.Instance, t *testing.T) {
 
 func testNegativeCase1(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("group_type", "infinitevol")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "volume" && instance.GetLabel("protectionSourceType") == "not_mapped" {
 		// OK
@@ -109,7 +108,7 @@ func testNegativeCase2(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("destination_volume", "destvol")
 	instance.SetLabel("source_volume", "sourcevol")
 	instance.SetLabel("destination_location", "test123:")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "volume" && instance.GetLabel("protectionSourceType") == "not_mapped" {
 		// OK
@@ -120,7 +119,7 @@ func testNegativeCase2(instance *matrix.Instance, t *testing.T) {
 
 func testGroupTypeNone(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("group_type", "none")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "volume" && instance.GetLabel("protectionSourceType") == "volume" {
 		// OK
@@ -131,7 +130,7 @@ func testGroupTypeNone(instance *matrix.Instance, t *testing.T) {
 
 func testGroupTypeFlexgroup(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("group_type", "flexgroup")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("protectedBy") == "volume" && instance.GetLabel("protectionSourceType") == "volume" {
 		// OK
@@ -144,7 +143,7 @@ func testGroupTypeFlexgroup(instance *matrix.Instance, t *testing.T) {
 func testStrictSyncMirror(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("relationship_type", "")
 	instance.SetLabel("policy_type", "strict_sync_mirror")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("derived_relationship_type") == "sync_mirror_strict" {
 		// OK
@@ -156,7 +155,7 @@ func testStrictSyncMirror(instance *matrix.Instance, t *testing.T) {
 func testSyncMirror(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("relationship_type", "")
 	instance.SetLabel("policy_type", "sync_mirror")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("derived_relationship_type") == "sync_mirror" {
 		// OK
@@ -168,7 +167,7 @@ func testSyncMirror(instance *matrix.Instance, t *testing.T) {
 func testMirrorVault(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("relationship_type", "")
 	instance.SetLabel("policy_type", "mirror_vault")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("derived_relationship_type") == "mirror_vault" {
 		// OK
@@ -180,7 +179,7 @@ func testMirrorVault(instance *matrix.Instance, t *testing.T) {
 func testAutomatedFailover(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("relationship_type", "")
 	instance.SetLabel("policy_type", "automated_failover")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("derived_relationship_type") == "sync_mirror" {
 		// OK
@@ -192,7 +191,7 @@ func testAutomatedFailover(instance *matrix.Instance, t *testing.T) {
 func testOtherPolicyType(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("relationship_type", "vault")
 	instance.SetLabel("policy_type", "vault")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("derived_relationship_type") == "vault" {
 		// OK
@@ -204,7 +203,7 @@ func testOtherPolicyType(instance *matrix.Instance, t *testing.T) {
 func testWithNoPolicyType(instance *matrix.Instance, t *testing.T) {
 	instance.SetLabel("relationship_type", "extended_data_protection")
 	instance.SetLabel("policy_type", "")
-	sm.updateProtectedFields(instance)
+	collectors.UpdateProtectedFields(instance)
 
 	if instance.GetLabel("derived_relationship_type") == "extended_data_protection" {
 		// OK