diff --git a/README.md b/README.md index 879f3057..20de3a6a 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ Name | Description | Enabled by default [scheduled_task](docs/collector.scheduled_task.md) | Scheduled Tasks metrics | [service](docs/collector.service.md) | Service state metrics | ✓ [smb](docs/collector.smb.md) | SMB Server | +[smbclient](docs/collector.smbclient.md) | SMB Client | [smtp](docs/collector.smtp.md) | IIS SMTP Server | [system](docs/collector.system.md) | System calls | ✓ [tcp](docs/collector.tcp.md) | TCP connections | diff --git a/docs/collector.smbclient.md b/docs/collector.smbclient.md new file mode 100644 index 00000000..0141986c --- /dev/null +++ b/docs/collector.smbclient.md @@ -0,0 +1,50 @@ +# smbclient collector +The smbclient collector collects metrics from MS SmbClient hosts through perflib +||| +-|- +Metric name prefix | `windows_smbclient` +Classes | [Win32_PerfRawData_SMB](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/)
+Enabled by default? | No + +## Flags + +### `--collectors.smbclient.list` +Lists the Perflib Objects that are queried for data along with the perlfib object id + +### `--collectors.smbclient.enabled` +Comma-separated list of collectors to use, for example: `--collectors.smbclient.enabled=ServerShares`. Matching is case-sensitive. Depending on the smb protocol version not all performance counters may be available. Use `--collectors.smbclient.list` to obtain a list of supported collectors. + +## Metrics +Name | Description | Type | Labels +-----|-------------|------|------- +`windows_smbclient_data_queue_seconds_total` | Seconds requests waited on queue on this share | counter | `server`, `share`| +`windows_smbclient_read_queue_seconds_total` | Seconds read requests waited on queue on this share | counter | `server`, `share`| +`windows_smbclient_write_queue_seconds_total` | Seconds write requests waited on queue on this share | counter | `server`, `share`| +`windows_smbclient_request_seconds_total` | Seconds waiting for requests on this share | counter | `server`, `share`| +`windows_smbclient_stalls_total` | The number of requests delayed based on insufficient credits on this share | counter | `server`, `share`| +`windows_smbclient_requests_queued` | The point in time (current) number of requests outstanding on this share | counter | `server`, `share`| +`windows_smbclient_data_bytes_total` | The bytes read or written on this share | counter | `server`, `share`| +`windows_smbclient_requests_total` | The requests on this share | counter | `server`, `share`| +`windows_smbclient_metadata_requests_total` | The metadata requests on this share | counter | `server`, `share`| +`windows_smbclient_read_bytes_via_smbdirect_total` | The bytes read from this share via RDMA direct placement | TBD | `server`, `share`| +`windows_smbclient_read_bytes_total` | The bytes read on this share | counter | `server`, `share`| +`windows_smbclient_read_requests_via_smbdirect_total` | The read requests on this share via RDMA direct placement | TBD | `server`, `share`| +`windows_smbclient_read_requests_total` | The read requests on this share | counter | `server`, `share`| +`windows_smbclient_turbo_io_reads_total` | The read requests that go through Turbo I/O | TBD | `server`, `share`| +`windows_smbclient_turbo_io_writes_total` | The write requests that go through Turbo I/O | TBD | `server`, `share`| +`windows_smbclient_write_bytes_via_smbdirect_total` | The written bytes to this share via RDMA direct placement | TBD | `server`, `share`| +`windows_smbclient_write_bytes_total` | The bytes written on this share | counter | `server`, `share`| +`windows_smbclient_write_requests_via_smbdirect_total` | The write requests to this share via RDMA direct placement | TBD | `server`, `share`| +`windows_smbclient_write_requests_total` | The write requests on this share | counter | `server`, `share`| +`windows_smbclient_read_seconds_total` | Seconds waiting for read requests on this share | counter | `server`, `share`| +`windows_smbclient_write_seconds_total` | Seconds waiting for write requests on this share | counter | `server`, `share`| +## Useful queries +``` +# Average request queue length (includes read and write). +irate(windows_smbclient_data_queue_seconds_total) +# Request latency milliseconds (includes read and write). +irate(windows_smbclient_request_seconds_total) / irate(windows_smbclient_requests_total) * 1000 +``` +## Alerting examples +_This collector does not yet have alerting examples, we would appreciate your help adding them!_ + diff --git a/pkg/collector/collector.go b/pkg/collector/collector.go index 297020b5..d53daa69 100644 --- a/pkg/collector/collector.go +++ b/pkg/collector/collector.go @@ -50,6 +50,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/collector/scheduled_task" "github.com/prometheus-community/windows_exporter/pkg/collector/service" "github.com/prometheus-community/windows_exporter/pkg/collector/smb" + "github.com/prometheus-community/windows_exporter/pkg/collector/smbclient" "github.com/prometheus-community/windows_exporter/pkg/collector/smtp" "github.com/prometheus-community/windows_exporter/pkg/collector/system" "github.com/prometheus-community/windows_exporter/pkg/collector/tcp" @@ -128,6 +129,7 @@ func NewWithConfig(logger log.Logger, config Config) Collectors { collectors[scheduled_task.Name] = scheduled_task.New(logger, &config.ScheduledTask) collectors[service.Name] = service.New(logger, &config.Service) collectors[smb.Name] = smb.New(logger, &config.Smb) + collectors[smbclient.Name] = smbclient.New(logger, &config.SmbClient) collectors[smtp.Name] = smtp.New(logger, &config.Smtp) collectors[system.Name] = system.New(logger, &config.System) collectors[teradici_pcoip.Name] = teradici_pcoip.New(logger, &config.TeradiciPcoip) diff --git a/pkg/collector/config.go b/pkg/collector/config.go index 3dde3226..9ea05144 100644 --- a/pkg/collector/config.go +++ b/pkg/collector/config.go @@ -43,6 +43,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/collector/scheduled_task" "github.com/prometheus-community/windows_exporter/pkg/collector/service" "github.com/prometheus-community/windows_exporter/pkg/collector/smb" + "github.com/prometheus-community/windows_exporter/pkg/collector/smbclient" "github.com/prometheus-community/windows_exporter/pkg/collector/smtp" "github.com/prometheus-community/windows_exporter/pkg/collector/system" "github.com/prometheus-community/windows_exporter/pkg/collector/tcp" @@ -99,6 +100,7 @@ type Config struct { ScheduledTask scheduled_task.Config `yaml:"scheduled_task"` Service service.Config `yaml:"service"` Smb smb.Config `yaml:"smb"` + SmbClient smbclient.Config `yaml:"smbclient"` Smtp smtp.Config `yaml:"smtp"` System system.Config `yaml:"system"` TeradiciPcoip teradici_pcoip.Config `yaml:"teradici_pcoip"` @@ -156,6 +158,7 @@ var ConfigDefaults = Config{ ScheduledTask: scheduled_task.ConfigDefaults, Service: service.ConfigDefaults, Smb: smb.ConfigDefaults, + SmbClient: smbclient.ConfigDefaults, Smtp: smtp.ConfigDefaults, System: system.ConfigDefaults, TeradiciPcoip: teradici_pcoip.ConfigDefaults, diff --git a/pkg/collector/map.go b/pkg/collector/map.go index 7a6d4daf..a5ddf706 100644 --- a/pkg/collector/map.go +++ b/pkg/collector/map.go @@ -44,6 +44,7 @@ import ( "github.com/prometheus-community/windows_exporter/pkg/collector/scheduled_task" "github.com/prometheus-community/windows_exporter/pkg/collector/service" "github.com/prometheus-community/windows_exporter/pkg/collector/smb" + "github.com/prometheus-community/windows_exporter/pkg/collector/smbclient" "github.com/prometheus-community/windows_exporter/pkg/collector/smtp" "github.com/prometheus-community/windows_exporter/pkg/collector/system" "github.com/prometheus-community/windows_exporter/pkg/collector/tcp" @@ -103,6 +104,7 @@ var Map = map[string]types.CollectorBuilderWithFlags{ scheduled_task.Name: scheduled_task.NewWithFlags, service.Name: service.NewWithFlags, smb.Name: smb.NewWithFlags, + smbclient.Name: smbclient.NewWithFlags, smtp.Name: smtp.NewWithFlags, system.Name: system.NewWithFlags, teradici_pcoip.Name: teradici_pcoip.NewWithFlags, diff --git a/pkg/collector/smbclient/smbclient.go b/pkg/collector/smbclient/smbclient.go new file mode 100644 index 00000000..94cb6ded --- /dev/null +++ b/pkg/collector/smbclient/smbclient.go @@ -0,0 +1,455 @@ +//go:build windows + +package smbclient + +import ( + "fmt" + "os" + "slices" + "strings" + + "github.com/alecthomas/kingpin/v2" + "github.com/go-kit/log" + "github.com/go-kit/log/level" + "github.com/prometheus-community/windows_exporter/pkg/perflib" + "github.com/prometheus-community/windows_exporter/pkg/types" + "github.com/prometheus/client_golang/prometheus" +) + +const ( + Name = "smbclient" + FlagSmbClientListAllCollectors = "collectors.smbclient.list" + FlagSmbClientCollectorsEnabled = "collectors.smbclient.enabled" +) + +type Config struct { + CollectorsEnabled string `yaml:"collectors_enabled"` +} + +var ConfigDefaults = Config{ + CollectorsEnabled: "", +} + +type collector struct { + logger log.Logger + + smbclientListAllCollectors *bool + smbclientCollectorsEnabled *string + + ReadRequestQueueSecsTotal *prometheus.Desc + ReadBytesTotal *prometheus.Desc + ReadsTotal *prometheus.Desc + ReadBytesTransmittedViaSMBDirectTotal *prometheus.Desc + ReadRequestsTransmittedViaSMBDirectTotal *prometheus.Desc + TurboIOReadsTotal *prometheus.Desc + ReadSecsTotal *prometheus.Desc + + WriteRequestQueueSecsTotal *prometheus.Desc + WriteBytesTotal *prometheus.Desc + WritesTotal *prometheus.Desc + WriteBytesTransmittedViaSMBDirectTotal *prometheus.Desc + WriteRequestsTransmittedViaSMBDirectTotal *prometheus.Desc + TurboIOWritesTotal *prometheus.Desc + WriteSecsTotal *prometheus.Desc + + RequestQueueSecsTotal *prometheus.Desc + RequestSecs *prometheus.Desc + CreditStallsTotal *prometheus.Desc + CurrentDataQueued *prometheus.Desc + DataBytesTotal *prometheus.Desc + DataRequestsTotal *prometheus.Desc + MetadataRequestsTotal *prometheus.Desc + + enabledCollectors []string +} + +// All available collector functions +var smbclientAllCollectorNames = []string{ + "ClientShares", +} + +func New(logger log.Logger, config *Config) types.Collector { + if config == nil { + config = &ConfigDefaults + } + + smbclientListAllCollectors := false + c := &collector{ + smbclientCollectorsEnabled: &config.CollectorsEnabled, + smbclientListAllCollectors: &smbclientListAllCollectors, + } + c.SetLogger(logger) + return c +} + +func NewWithFlags(app *kingpin.Application) types.Collector { + return &collector{ + smbclientListAllCollectors: app.Flag( + FlagSmbClientListAllCollectors, + "List the collectors along with their perflib object name/ids", + ).Bool(), + + smbclientCollectorsEnabled: app.Flag( + FlagSmbClientCollectorsEnabled, + "Comma-separated list of collectors to use. Defaults to all, if not specified.", + ).Default(ConfigDefaults.CollectorsEnabled).String(), + } +} + +func (c *collector) GetName() string { + return Name +} + +func (c *collector) SetLogger(logger log.Logger) { + c.logger = log.With(logger, "collector", Name) +} + +func (c *collector) GetPerfCounter() ([]string, error) { + return []string{ + "SMB Client Shares", + }, nil +} + +func (c *collector) Build() error { + // desc creates a new prometheus description + desc := func(metricName string, description string, labels []string) *prometheus.Desc { + return prometheus.NewDesc( + prometheus.BuildFQName(types.Namespace, "smbclient", metricName), + description, + labels, + nil, + ) + } + + c.RequestQueueSecsTotal = desc("data_queue_seconds_total", + "Seconds requests waited on queue on this share", + []string{"server", "share"}, + ) + c.ReadRequestQueueSecsTotal = desc("read_queue_seconds_total", + "Seconds read requests waited on queue on this share", + []string{"server", "share"}, + ) + c.WriteRequestQueueSecsTotal = desc("write_queue_seconds_total", + "Seconds write requests waited on queue on this share", + []string{"server", "share"}, + ) + c.RequestSecs = desc("request_seconds_total", + "Seconds waiting for requests on this share", + []string{"server", "share"}, + ) + c.CreditStallsTotal = desc("stalls_total", + "The number of requests delayed based on insufficient credits on this share", + []string{"server", "share"}, + ) + c.CurrentDataQueued = desc("requests_queued", + "The point in time number of requests outstanding on this share", + []string{"server", "share"}, + ) + c.DataBytesTotal = desc("data_bytes_total", + "The bytes read or written on this share", + []string{"server", "share"}, + ) + c.DataRequestsTotal = desc("requests_total", + "The requests on this share", + []string{"server", "share"}, + ) + c.MetadataRequestsTotal = desc("metadata_requests_total", + "The metadata requests on this share", + []string{"server", "share"}, + ) + c.ReadBytesTransmittedViaSMBDirectTotal = desc("read_bytes_via_smbdirect_total", + "The bytes read from this share via RDMA direct placement", + []string{"server", "share"}, + ) + c.ReadBytesTotal = desc("read_bytes_total", + "The bytes read on this share", + []string{"server", "share"}, + ) + c.ReadRequestsTransmittedViaSMBDirectTotal = desc("read_requests_via_smbdirect_total", + "The read requests on this share via RDMA direct placement", + []string{"server", "share"}, + ) + c.ReadsTotal = desc("read_requests_total", + "The read requests on this share", + []string{"server", "share"}, + ) + c.TurboIOReadsTotal = desc("turbo_io_reads_total", + "The read requests that go through Turbo I/O", + []string{"server", "share"}, + ) + c.TurboIOWritesTotal = desc("turbo_io_writes_total", + "The write requests that go through Turbo I/O", + []string{"server", "share"}, + ) + c.WriteBytesTransmittedViaSMBDirectTotal = desc("write_bytes_via_smbdirect_total", + "The written bytes to this share via RDMA direct placement", + []string{"server", "share"}, + ) + c.WriteBytesTotal = desc("write_bytes_total", + "The bytes written on this share", + []string{"server", "share"}, + ) + c.WriteRequestsTransmittedViaSMBDirectTotal = desc("write_requests_via_smbdirect_total", + "The write requests to this share via RDMA direct placement", + []string{"server", "share"}, + ) + c.WritesTotal = desc("write_requests_total", + "The write requests on this share", + []string{"server", "share"}, + ) + c.ReadSecsTotal = desc("read_seconds_total", + "Seconds waiting for read requests on this share", + []string{"server", "share"}, + ) + c.WriteSecsTotal = desc("write_seconds_total", + "Seconds waiting for write requests on this share", + []string{"server", "share"}, + ) + + c.enabledCollectors = make([]string, 0, len(smbclientAllCollectorNames)) + + collectorDesc := map[string]string{ + "ClientShares": "SMB Client Shares", + } + + if *c.smbclientListAllCollectors { + fmt.Printf("%-32s %-32s\n", "Collector Name", "Perflib Object") + for _, cname := range smbclientAllCollectorNames { + fmt.Printf("%-32s %-32s\n", cname, collectorDesc[cname]) + } + os.Exit(0) + } + + if *c.smbclientCollectorsEnabled == "" { + for _, collectorName := range smbclientAllCollectorNames { + c.enabledCollectors = append(c.enabledCollectors, collectorName) + } + } else { + for _, collectorName := range strings.Split(*c.smbclientCollectorsEnabled, ",") { + if slices.Contains(smbclientAllCollectorNames, collectorName) { + c.enabledCollectors = append(c.enabledCollectors, collectorName) + } else { + return fmt.Errorf("unknown smbclient collector: %s", collectorName) + } + } + } + + return nil +} + +// Collect collects smb client metrics and sends them to prometheus +func (c *collector) Collect(ctx *types.ScrapeContext, ch chan<- prometheus.Metric) error { + collectorFuncs := map[string]func(ctx *types.ScrapeContext, ch chan<- prometheus.Metric) error{ + "ClientShares": c.collectClientShares, + } + + for _, collectorName := range c.enabledCollectors { + if err := collectorFuncs[collectorName](ctx, ch); err != nil { + _ = level.Error(c.logger).Log("msg", "Error in "+collectorName, "err", err) + return err + } + } + return nil +} + +// Perflib: SMB Client Shares +type perflibClientShares struct { + Name string + + AvgDataQueueLength float64 `perflib:"Avg. Data Queue Length"` + AvgReadQueueLength float64 `perflib:"Avg. Read Queue Length"` + AvgSecPerRead float64 `perflib:"Avg. sec/Read"` + AvgSecPerWrite float64 `perflib:"Avg. sec/Write"` + AvgSecPerDataRequest float64 `perflib:"Avg. sec/Data Request"` + AvgWriteQueueLength float64 `perflib:"Avg. Write Queue Length"` + CreditStallsPerSec float64 `perflib:"Credit Stalls/sec"` + CurrentDataQueueLength float64 `perflib:"Current Data Queue Length"` + DataBytesPerSec float64 `perflib:"Data Bytes/sec"` + DataRequestsPerSec float64 `perflib:"Data Requests/sec"` + MetadataRequestsPerSec float64 `perflib:"Metadata Requests/sec"` + ReadBytesTransmittedViaSMBDirectPerSec float64 `perflib:"Read Bytes transmitted via SMB Direct/sec"` + ReadBytesPerSec float64 `perflib:"Read Bytes/sec"` + ReadRequestsTransmittedViaSMBDirectPerSec float64 `perflib:"Read Requests transmitted via SMB Direct/sec"` + ReadRequestsPerSec float64 `perflib:"Read Requests/sec"` + TurboIOReadsPerSec float64 `perflib:"Turbo I/O Reads/sec"` + TurboIOWritesPerSec float64 `perflib:"Turbo I/O Writes/sec"` + WriteBytesTransmittedViaSMBDirectPerSec float64 `perflib:"Write Bytes transmitted via SMB Direct/sec"` + WriteBytesPerSec float64 `perflib:"Write Bytes/sec"` + WriteRequestsTransmittedViaSMBDirectPerSec float64 `perflib:"Write Requests transmitted via SMB Direct/sec"` + WriteRequestsPerSec float64 `perflib:"Write Requests/sec"` +} + +func (c *collector) collectClientShares(ctx *types.ScrapeContext, ch chan<- prometheus.Metric) error { + var data []perflibClientShares + if err := perflib.UnmarshalObject(ctx.PerfObjects["SMB Client Shares"], &data, c.logger); err != nil { + return err + } + for _, instance := range data { + // labelName := c.toLabelName(instance.Name) + if instance.Name == "_Total" { + continue + } + + parsed := strings.FieldsFunc(instance.Name, func(r rune) bool { return r == '\\' }) + serverValue := parsed[0] + shareValue := parsed[1] + // Request time spent on queue. Convert from ticks to seconds. + ch <- prometheus.MustNewConstMetric( + c.RequestQueueSecsTotal, + prometheus.CounterValue, + instance.AvgDataQueueLength*perflib.TicksToSecondScaleFactor, + serverValue, shareValue, + ) + + // Read time spent on queue. Convert from ticks to seconds. + ch <- prometheus.MustNewConstMetric( + c.ReadRequestQueueSecsTotal, + prometheus.CounterValue, + instance.AvgReadQueueLength*perflib.TicksToSecondScaleFactor, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.ReadSecsTotal, + prometheus.CounterValue, + instance.AvgSecPerRead*perflib.TicksToSecondScaleFactor, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.WriteSecsTotal, + prometheus.CounterValue, + instance.AvgSecPerWrite*perflib.TicksToSecondScaleFactor, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.RequestSecs, + prometheus.CounterValue, + instance.AvgSecPerDataRequest*perflib.TicksToSecondScaleFactor, + serverValue, shareValue, + ) + + // Write time spent on queue. Convert from ticks to seconds. + ch <- prometheus.MustNewConstMetric( + c.WriteRequestQueueSecsTotal, + prometheus.CounterValue, + instance.AvgWriteQueueLength*perflib.TicksToSecondScaleFactor, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.CreditStallsTotal, + prometheus.CounterValue, + instance.CreditStallsPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.CurrentDataQueued, + prometheus.GaugeValue, + instance.CurrentDataQueueLength, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.DataBytesTotal, + prometheus.CounterValue, + instance.DataBytesPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.DataRequestsTotal, + prometheus.CounterValue, + instance.DataRequestsPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.MetadataRequestsTotal, + prometheus.CounterValue, + instance.MetadataRequestsPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.ReadBytesTransmittedViaSMBDirectTotal, + prometheus.CounterValue, + instance.ReadBytesTransmittedViaSMBDirectPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.ReadBytesTotal, + prometheus.CounterValue, + instance.ReadBytesPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.ReadRequestsTransmittedViaSMBDirectTotal, + prometheus.CounterValue, + instance.ReadRequestsTransmittedViaSMBDirectPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.ReadsTotal, + prometheus.CounterValue, + instance.ReadRequestsPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.TurboIOReadsTotal, + prometheus.CounterValue, + instance.TurboIOReadsPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.TurboIOWritesTotal, + prometheus.CounterValue, + instance.TurboIOWritesPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.WriteBytesTransmittedViaSMBDirectTotal, + prometheus.CounterValue, + instance.WriteBytesTransmittedViaSMBDirectPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.WriteBytesTotal, + prometheus.CounterValue, + instance.WriteBytesPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.WriteRequestsTransmittedViaSMBDirectTotal, + prometheus.CounterValue, + instance.WriteRequestsTransmittedViaSMBDirectPerSec, + serverValue, shareValue, + ) + + ch <- prometheus.MustNewConstMetric( + c.WritesTotal, + prometheus.CounterValue, + instance.WriteRequestsPerSec, + serverValue, shareValue, + ) + + } + return nil +} + +// toLabelName converts strings to lowercase and replaces all whitespaces and dots with underscores +func (c *collector) toLabelName(name string) string { + s := strings.ReplaceAll(strings.Join(strings.Fields(strings.ToLower(name)), "_"), ".", "_") + s = strings.ReplaceAll(s, "__", "_") + return s +} diff --git a/pkg/collector/smbclient/smbclient_test.go b/pkg/collector/smbclient/smbclient_test.go new file mode 100644 index 00000000..e7665379 --- /dev/null +++ b/pkg/collector/smbclient/smbclient_test.go @@ -0,0 +1,12 @@ +package smbclient_test + +import ( + "testing" + + "github.com/prometheus-community/windows_exporter/pkg/collector/smbclient" + "github.com/prometheus-community/windows_exporter/pkg/testutils" +) + +func BenchmarkCollector(b *testing.B) { + testutils.FuncBenchmarkCollector(b, smbclient.Name, smbclient.NewWithFlags) +}