func (s *service) getStorageArrayLength() (length int) {
	length = 0
	s.arrays.Range(func(_, _ interface{}) bool {
		length++
		return true
	})
	return
}
Returns the size of arrays
package service
import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"net"
	"path/filepath"
	"strconv"
	"strings"
	"regexp"
	"sync"
	"sync/atomic"
	"time"
	"os"
	"github.com/dell/dell-csi-extensions/podmon"
	"google.golang.org/grpc"
	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"github.com/container-storage-interface/spec/lib/go/csi"
	"github.com/dell/csi-unity/common"
	"github.com/dell/csi-unity/core"
	"github.com/dell/csi-unity/k8sutils"
	"github.com/dell/csi-unity/service/utils"
	"github.com/dell/gobrick"
	"github.com/dell/gocsi"
	csictx "github.com/dell/gocsi/context"
	"github.com/dell/goiscsi"
	"github.com/dell/gounity"
	"github.com/dell/gounity/util"
	"github.com/fsnotify/fsnotify"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
	"gopkg.in/yaml.v3"
)
const (
	VendorVersion = "0.0.0"
	TcpDialTimeout = 1000
	IScsiPort = "3260"
)
var Name string
var DriverConfig string
var DriverSecret string
var runid int64
var Manifest = map[string]string{
	"url":    "http://github.com/dell/csi-unity",
	"semver": core.SemVer,
	"commit": core.CommitSha32,
	"formed": core.CommitTime.Format(time.RFC1123),
}
type StorageArrayList struct {
	StorageArrayList []StorageArrayConfig `yaml:"storageArrayList"`
}
type StorageArrayConfig struct {
	ArrayId                   string `yaml:"arrayId"`
	Username                  string `yaml:"username"`
	Password                  string `yaml:"password"`
	Endpoint                  string `yaml:"endpoint"`
	IsDefault                 *bool  `yaml:"isDefault,omitempty"`
	SkipCertificateValidation *bool  `yaml:"skipCertificateValidation,omitempty"`
	IsProbeSuccess            bool
	IsHostAdded               bool
	IsDefaultArray            bool
	UnityClient               *gounity.Client
}
type Service interface {
	csi.ControllerServer
	csi.IdentityServer
	csi.NodeServer
	BeforeServe(context.Context, *gocsi.StoragePlugin, net.Listener) error
	RegisterAdditionalServers(*grpc.Server)
}
type Opts struct {
	NodeName                      string
	LongNodeName                  string
	Chroot                        string
	Thick                         bool
	AutoProbe                     bool
	AllowRWOMultiPodAccess        bool
	PvtMountDir                   string
	Debug                         bool
	SyncNodeInfoTimeInterval      int64
	EnvEphemeralStagingTargetPath string
	KubeConfigPath                string
	MaxVolumesPerNode             int64
	LogLevel                      string
}
type service struct {
	opts           Opts
	arrays         *sync.Map
	mode           string
	iscsiClient    goiscsi.ISCSIinterface
	fcConnector    fcConnector  
	iscsiConnector iSCSIConnector
}
type iSCSIConnector interface {
	ConnectVolume(ctx context.Context, info gobrick.ISCSIVolumeInfo) (gobrick.Device, error)
	DisconnectVolumeByDeviceName(ctx context.Context, name string) error
	GetInitiatorName(ctx context.Context) ([]string, error)
}
type fcConnector interface {
	ConnectVolume(ctx context.Context, info gobrick.FCVolumeInfo) (gobrick.Device, error)
	DisconnectVolumeByDeviceName(ctx context.Context, name string) error
	GetInitiatorPorts(ctx context.Context) ([]string, error)
}
func New() Service {
	return &service{}
}
func (s StorageArrayConfig) String() string {
	return fmt.Sprintf("ArrayID: %s, Username: %s, Endpoint: %s, SkipCertificateValidation: %v, IsDefaultArray:%v, IsProbeSuccess:%v, IsHostAdded:%v",
		s.ArrayId, s.Username, s.Endpoint, s.SkipCertificateValidation, s.IsDefaultArray, s.IsProbeSuccess, s.IsHostAdded)
}
func (s *service) BeforeServe(
	ctx context.Context, sp *gocsi.StoragePlugin, lis net.Listener) error {
	ctx, log := setRunIdContext(ctx, "start")
	var err error
	defer func() {
		fields := map[string]interface{}{
			"nodename":  s.opts.NodeName,
			"autoprobe": s.opts.AutoProbe,
			"mode":      s.mode,
		}
		log.WithFields(fields).Infof("configured %s", Name)
	}()
	s.mode = csictx.Getenv(ctx, gocsi.EnvVarMode)
	log.Info("Driver Mode:", s.mode)
	opts := Opts{}
	if name, ok := csictx.LookupEnv(ctx, gocsi.EnvVarDebug); ok {
		opts.Debug, _ = strconv.ParseBool(name)
	}
	if name, ok := csictx.LookupEnv(ctx, EnvNodeName); ok {
		log.Infof("%s: %s", EnvNodeName, name)
		opts.LongNodeName = name
		var shortHostName string
		var ipFormat = regexp.MustCompile(`(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}`)
		if (ipFormat.MatchString(name)) {
			shortHostName = name
		}else{
			shortHostName = strings.Split(name, ".")[0]
		}
		opts.NodeName = shortHostName
	}
	if kubeConfigPath, ok := csictx.LookupEnv(ctx, EnvKubeConfigPath); ok {
		opts.KubeConfigPath = kubeConfigPath
	}
	pb := func(n string) bool {
		if v, ok := csictx.LookupEnv(ctx, n); ok {
			b, err := strconv.ParseBool(v)
			if err != nil {
				log.WithField(n, v).Warn(
					"invalid boolean value. defaulting to false")
				return false
			}
			return b
		}
		return false
	}
	opts.MaxVolumesPerNode = 0  
	if syncNodeInfoTimeInterval, ok := csictx.LookupEnv(ctx, SyncNodeInfoTimeInterval); ok {
		opts.SyncNodeInfoTimeInterval, err = strconv.ParseInt(syncNodeInfoTimeInterval, 10, 64)
		log.Debugf("SyncNodeInfoTimeInterval %d", opts.SyncNodeInfoTimeInterval)
		if err != nil {
			log.Warn("Failed to parse syncNodeInfoTimeInterval provided by user, hence reverting to default value")
			opts.SyncNodeInfoTimeInterval = 15
		}
	}
	opts.AllowRWOMultiPodAccess = pb(EnvAllowRWOMultiPodAccess)
	if opts.AllowRWOMultiPodAccess {
		log.Warn("AllowRWOMultiPodAccess has been set to true. PVCs will now be accessible by multiple pods on the same node.")
	}
	opts.AutoProbe = pb(EnvAutoProbe)
	if pvtmountDir, ok := csictx.LookupEnv(ctx, EnvPvtMountDir); ok {
		opts.PvtMountDir = pvtmountDir
	}
	if ephemeralStagePath, ok := csictx.LookupEnv(ctx, EnvEphemeralStagingPath); ok {
		opts.EnvEphemeralStagingTargetPath = ephemeralStagePath
	}
	iscsiOpts := make(map[string]string, 0)
	if chroot, ok := csictx.LookupEnv(ctx, EnvISCSIChroot); ok {
		iscsiOpts[goiscsi.ChrootDirectory] = chroot
		opts.Chroot = chroot
	}
	s.iscsiClient = goiscsi.NewLinuxISCSI(iscsiOpts)
	s.opts = opts
	runid := fmt.Sprintf("config-%d", 0)
	ctx, log = setRunIdContext(ctx, runid)
	s.arrays = new(sync.Map)
	err = s.syncDriverSecret(ctx)
	if err != nil {
		return err
	}
	syncNodeInfoChan = make(chan bool)
	go s.loadDynamicConfig(ctx, DriverSecret, DriverConfig)
	if s.mode == "node" {
		if s.opts.NodeName == "" {
			return status.Error(codes.InvalidArgument, "'Node Name' has not been configured. Set environment variable X_CSI_UNITY_NODENAME")
		}
		go s.syncNodeInfoRoutine(ctx)
		syncNodeInfoChan <- true
	}
	return nil
}
func (s *service) RegisterAdditionalServers(server *grpc.Server) {
	_, log := setRunIdContext(context.Background(), "RegisterAdditionalServers")
	log.Info("Registering additional GRPC servers")
	podmon.RegisterPodmonServer(server, s)
}
func (s *service) getStorageArray(arrayID string) *StorageArrayConfig {
	if a, ok := s.arrays.Load(arrayID); ok {
		return a.(*StorageArrayConfig)
	}
	return nil
}