diff --git a/go_exporter/RBDFactory.go b/go_exporter/RBDFactory.go
index 3cad87c..f36f070 100644
--- a/go_exporter/RBDFactory.go
+++ b/go_exporter/RBDFactory.go
@@ -28,7 +28,7 @@ func PoolFactory(cephConn CephConnector, poolName string) (Pool, error) {
}
return Pool{
Name: poolName,
- hasRBD: len(imageList) != 0,
+ HasRBD: len(imageList) != 0,
RBDlist: rbdlist,
}, nil
}
@@ -36,7 +36,7 @@ func PoolFactory(cephConn CephConnector, poolName string) (Pool, error) {
func RBDFacroty(ioctx IOContexter, rbdname string) (RBD, error) {
defer func() {
if v := recover(); v != nil {
- fmt.Println("Shit happened")
+ fmt.Println("Shit happened in RBDFactory")
}
}()
diff --git a/go_exporter/connection.go b/go_exporter/connection.go
index 083ff67..35b4d8d 100644
--- a/go_exporter/connection.go
+++ b/go_exporter/connection.go
@@ -20,12 +20,12 @@ func connect() (_ CephConnection, err error) {
return CephConnection{}, err
}
- err = cephConn.conn.ReadConfigFile(params.config)
+ err = cephConn.conn.ReadConfigFile(params.Config)
if err != nil {
return CephConnection{}, err
}
- err = cephConn.conn.SetConfigOption("keyring", params.keyring)
+ err = cephConn.conn.SetConfigOption("keyring", params.Keyring)
if err != nil {
return CephConnection{}, err
}
diff --git a/go_exporter/getOpts.go b/go_exporter/getOpts.go
index 331352c..b542486 100644
--- a/go_exporter/getOpts.go
+++ b/go_exporter/getOpts.go
@@ -16,8 +16,8 @@ func init() {
_keyring := flag.String("keyring", "/etc/ceph/ceph.client.admin.keyring", "placement of ceph keyring file")
flag.Parse()
- params.config = *config_file
- params.keyring = *_keyring
+ params.Config = *config_file
+ params.Keyring = *_keyring
logger = loggerInit()
logger.Info("Setting up logger is complete successfully")
diff --git a/go_exporter/go.mod b/go_exporter/go.mod
index de4f279..0bc9075 100644
--- a/go_exporter/go.mod
+++ b/go_exporter/go.mod
@@ -3,19 +3,11 @@ module main.go
go 1.25.5
require (
- github.com/ceph/go-ceph v0.36.0
+ github.com/ceph/go-ceph v0.37.0
github.com/prometheus/client_golang v1.23.2
go.uber.org/zap v1.27.1
)
-require (
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/kylelemons/godebug v1.1.0 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/stretchr/objx v0.5.2 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
-
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -23,9 +15,8 @@ require (
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.66.1 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
- github.com/stretchr/testify v1.11.1
go.uber.org/multierr v1.10.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
- golang.org/x/sys v0.36.0 // indirect
+ golang.org/x/sys v0.38.0 // indirect
google.golang.org/protobuf v1.36.8 // indirect
)
diff --git a/go_exporter/go.sum b/go_exporter/go.sum
index 900c68a..af21308 100644
--- a/go_exporter/go.sum
+++ b/go_exporter/go.sum
@@ -1,13 +1,13 @@
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/ceph/go-ceph v0.36.0 h1:IDE4vEF+4fmjve+CPjD1WStgfQ+Lh6vD+9PMUI712KI=
-github.com/ceph/go-ceph v0.36.0/go.mod h1:fGCbndVDLuHW7q2954d6y+tgPFOBnRLqJRe2YXyngw4=
+github.com/ceph/go-ceph v0.37.0 h1:KXliBe3ZDr3/AtfY7n9d1MG7ippYNCVhMPcAgm05CFI=
+github.com/ceph/go-ceph v0.37.0/go.mod h1:3y2tOlITlyuVFhy8v6PpCEfjMwKPfXJiH0/2hKZZQRE=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/gofrs/uuid/v5 v5.3.2 h1:2jfO8j3XgSwlz/wHqemAEugfnTlikAYHhnqQ8Xh4fE0=
-github.com/gofrs/uuid/v5 v5.3.2/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
+github.com/gofrs/uuid/v5 v5.4.0 h1:EfbpCTjqMuGyq5ZJwxqzn3Cbr2d0rUZU7v5ycAk/e/0=
+github.com/gofrs/uuid/v5 v5.4.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
@@ -32,8 +32,6 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
-github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -44,8 +42,8 @@ go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
-golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
-golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
diff --git a/go_exporter/main.go b/go_exporter/main.go
index 8bb9f91..8044dfc 100644
--- a/go_exporter/main.go
+++ b/go_exporter/main.go
@@ -6,7 +6,6 @@ import (
"net/http"
"os"
"time"
-
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.uber.org/zap"
@@ -19,7 +18,7 @@ func getMetrics(cephConn CephConnector) {
metrics := InitMetrics()
prometheus.MustRegister(
- metrics.total_rbd_requested_size_per_pool,
+ metrics.Total_rbd_requested_size_per_pool,
)
ticker := time.NewTicker(2 * time.Second)
@@ -39,9 +38,9 @@ func getMetrics(cephConn CephConnector) {
result = append(result, x)
}
- metrics.total_rbd_requested_size_per_pool.Reset()
+ metrics.Total_rbd_requested_size_per_pool.Reset()
for _,v := range result {
- if !v.hasRBD {continue}
+ if !v.HasRBD {continue}
FillMetrics(v,metrics)
}
fmt.Println("====================")
diff --git a/go_exporter/metrics.go b/go_exporter/metrics.go
index ab5c0e4..cfc420a 100644
--- a/go_exporter/metrics.go
+++ b/go_exporter/metrics.go
@@ -6,7 +6,7 @@ import (
func InitMetrics() *Metrics {
m := &Metrics{
- total_rbd_requested_size_per_pool: prometheus.NewGaugeVec(
+ Total_rbd_requested_size_per_pool: prometheus.NewGaugeVec(
prometheus.GaugeOpts{
Name: "total_rbd_requested_size_per_pool",
Help: "total size of all requested RBDs in a specific pool",
@@ -30,11 +30,11 @@ func FillMetrics(pool Pool,metrics *Metrics) {
logger.Debugf("Processing pool %s",pool.Name)
for _,v := range pool.RBDlist {
- totalSizePerPool += uint64(v.getSize())
+ totalSizePerPool += uint64(v.GetSize())
}
logger.Debugf("Total size of RBDs in pool %s is %d",pool.Name,totalSizePerPool)
- metrics.total_rbd_requested_size_per_pool.WithLabelValues(pool.Name,
+ metrics.Total_rbd_requested_size_per_pool.WithLabelValues(pool.Name,
).Set(
float64(totalSizePerPool))
diff --git a/go_exporter/mock_test.go b/go_exporter/mock_test.go
deleted file mode 100644
index 15c1100..0000000
--- a/go_exporter/mock_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package main
-
-import (
- "github.com/ceph/go-ceph/rbd"
- "github.com/stretchr/testify/mock"
-)
-
-// MockCephConnector
-type MockCephConnector struct {
- mock.Mock
-}
-
-func (m *MockCephConnector) ListPools() ([]string, error) {
- args := m.Called()
- return args.Get(0).([]string), args.Error(1)
-}
-
-func (m *MockCephConnector) OpenIOContext(poolName string) (IOContexter, error) {
- args := m.Called(poolName)
- if args.Get(0) == nil {
- return nil, args.Error(1)
- }
- return args.Get(0).(IOContexter), args.Error(1)
-}
-
-// MockIOContexter
-type MockIOContexter struct {
- mock.Mock
-}
-
-func (m *MockIOContexter) Destroy() {
- m.Called()
-}
-
-func (m *MockIOContexter) GetImageNames() ([]string, error) {
- args := m.Called()
- return args.Get(0).([]string), args.Error(1)
-}
-
-func (m *MockIOContexter) GetImage(name string) RBDImager {
- args := m.Called(name)
- return args.Get(0).(RBDImager)
-}
-
-// MockRBDImager
-type MockRBDImager struct {
- mock.Mock
-}
-
-func (m *MockRBDImager) Open() error {
- args := m.Called()
- return args.Error(0)
-}
-
-func (m *MockRBDImager) Close() error {
- args := m.Called()
- return args.Error(0)
-}
-
-func (m *MockRBDImager) Stat() (*rbd.ImageInfo, error) {
- args := m.Called()
- if args.Get(0) == nil {
- return nil, args.Error(1)
- }
- return args.Get(0).(*rbd.ImageInfo), args.Error(1)
-}
\ No newline at end of file
diff --git a/go_exporter/types.go b/go_exporter/types.go
index 9a21094..42dc068 100644
--- a/go_exporter/types.go
+++ b/go_exporter/types.go
@@ -7,8 +7,8 @@ import (
)
type Params struct {
- config string
- keyring string
+ Config string
+ Keyring string
}
type CephConnector interface {
@@ -82,8 +82,8 @@ func (riw RBDImageWrapper) Stat() (*rbd.ImageInfo,error) {
}
type iRBD interface {
- getName() string
- getSize() int64
+ GetName() string
+ GetSize() int64
}
type RBDUsage struct {
@@ -95,21 +95,21 @@ type RBD struct {
rbd.ImageInfo
}
-func (r RBD) getName() string {
+func (r RBD) GetName() string {
return r.Name
}
-func (r RBD) getSize() int64 {
+func (r RBD) GetSize() int64 {
return int64(r.Size)
}
type Pool struct {
Name string
- hasRBD bool
+ HasRBD bool
RBDlist []iRBD
}
type Metrics struct {
- total_rbd_requested_size_per_pool *prometheus.GaugeVec
- total_rbd_requested_size prometheus.Gauge
+ Total_rbd_requested_size_per_pool *prometheus.GaugeVec
+ Total_rbd_requested_size prometheus.Gauge
}
\ No newline at end of file
diff --git a/mod_prj/go.mod b/mod_prj/go.mod
new file mode 100644
index 0000000..6173058
--- /dev/null
+++ b/mod_prj/go.mod
@@ -0,0 +1,3 @@
+module mod_prj
+
+go 1.25.5
diff --git a/mod_prj/main.go b/mod_prj/main.go
new file mode 100644
index 0000000..119ee74
--- /dev/null
+++ b/mod_prj/main.go
@@ -0,0 +1,10 @@
+package main
+
+
+import "mod_prj/message"
+
+func main() {
+
+ messages.Hello_en()
+ messages.Bye_en()
+}
diff --git a/mod_prj/message/message.go b/mod_prj/message/message.go
new file mode 100644
index 0000000..42ba198
--- /dev/null
+++ b/mod_prj/message/message.go
@@ -0,0 +1,11 @@
+package messages
+import "fmt"
+
+func Hello_en() {
+
+ fmt.Println("Hello")
+}
+func Bye_en() {
+
+ fmt.Println("Good Bye")
+}
\ No newline at end of file
diff --git a/rbd_exporter/RBDFactory/RBDFactory.go b/rbd_exporter/RBDFactory/RBDFactory.go
new file mode 100644
index 0000000..217e1f7
--- /dev/null
+++ b/rbd_exporter/RBDFactory/RBDFactory.go
@@ -0,0 +1,64 @@
+package RBDFactory
+
+import (
+ "fmt"
+ "rbd_exporter/logger"
+ "rbd_exporter/mytypes"
+)
+
+func PoolFactory(cephConn mytypes.CephConnector, poolName string) (mytypes.Pool, error) {
+ var rbdlist []mytypes.IRBD = []mytypes.IRBD{}
+
+ ioctx, err := cephConn.OpenIOContext(poolName)
+ if err != nil {
+ return mytypes.Pool{}, fmt.Errorf("Couldn't set context for pool %s %w", poolName, err)
+ }
+
+ defer ioctx.Destroy()
+
+ imageList, err := ioctx.GetImageNames()
+ if err != nil {
+ return mytypes.Pool{}, fmt.Errorf("Couldn't get list of rbds %w", err)
+ }
+ for _, rbdname := range imageList {
+ stat, err := RBDFacroty(ioctx, rbdname)
+ if err != nil {
+ fmt.Errorf("Coundn't get stat from disk %s %w", rbdname, err)
+ panic(err)
+ }
+ rbdlist = append(rbdlist, stat)
+ }
+ return mytypes.Pool{
+ Name: poolName,
+ HasRBD: len(imageList) != 0,
+ RBDlist: rbdlist,
+ }, nil
+}
+
+func RBDFacroty(ioctx mytypes.IOContexter, rbdname string) (mytypes.RBD, error) {
+ defer func() {
+ if v := recover(); v != nil {
+ logger.Logger.Errorf("No such RBD exists (probably just deleted)")
+ }
+ }()
+
+ image := ioctx.GetImage(rbdname)
+ err := image.Open()
+ if err != nil {
+ panic(err)
+ // logger.Logger.Errorf("Shit happened in RBDFactory")
+ }
+
+ defer image.Close()
+
+
+ info,err := image.Stat()
+ if err != nil {
+ return mytypes.RBD{},fmt.Errorf("Couldn't get stats for image %s %w",rbdname,err)
+ }
+
+ return mytypes.RBD{
+ Name: rbdname,
+ ImageInfo: *info,
+ },nil
+}
diff --git a/rbd_exporter/connection/connection.go b/rbd_exporter/connection/connection.go
new file mode 100644
index 0000000..ca51edf
--- /dev/null
+++ b/rbd_exporter/connection/connection.go
@@ -0,0 +1,39 @@
+package connection
+
+import (
+ "fmt"
+ "rbd_exporter/mytypes"
+ "github.com/ceph/go-ceph/rados"
+)
+
+func Connect(params mytypes.Params) (_ mytypes.CephConnection, err error) {
+ var cephConn mytypes.CephConnection = mytypes.CephConnection{}
+
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("Error in func connect() %w", err)
+ }
+ }()
+
+ cephConn.Conn, err = rados.NewConnWithClusterAndUser("ceph", "client.admin")
+ if err != nil {
+ return mytypes.CephConnection{}, err
+ }
+
+ err = cephConn.Conn.ReadConfigFile(params.Config)
+ if err != nil {
+ return mytypes.CephConnection{}, err
+ }
+
+ err = cephConn.Conn.SetConfigOption("keyring", params.Keyring)
+ if err != nil {
+ return mytypes.CephConnection{}, err
+ }
+
+ err = cephConn.Conn.Connect()
+ if err != nil {
+ return mytypes.CephConnection{}, err
+ }
+
+ return cephConn, nil
+}
diff --git a/rbd_exporter/go.mod b/rbd_exporter/go.mod
new file mode 100644
index 0000000..3925caa
--- /dev/null
+++ b/rbd_exporter/go.mod
@@ -0,0 +1,29 @@
+module rbd_exporter
+
+go 1.25.5
+
+require github.com/prometheus/client_golang v1.23.2
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/golang/mock v1.6.0 // indirect
+ github.com/pmezard/go-difflib v1.0.0 // indirect
+ go.uber.org/mock v0.6.0 // indirect
+ go.uber.org/multierr v1.10.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+)
+
+require (
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/ceph/go-ceph v0.37.0
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/prometheus/client_model v0.6.2 // indirect
+ github.com/prometheus/common v0.66.1 // indirect
+ github.com/prometheus/procfs v0.16.1 // indirect
+ github.com/stretchr/testify v1.11.1
+ go.uber.org/zap v1.27.1
+ go.yaml.in/yaml/v2 v2.4.2 // indirect
+ golang.org/x/sys v0.38.0 // indirect
+ google.golang.org/protobuf v1.36.8 // indirect
+)
diff --git a/rbd_exporter/go.sum b/rbd_exporter/go.sum
new file mode 100644
index 0000000..64ca904
--- /dev/null
+++ b/rbd_exporter/go.sum
@@ -0,0 +1,64 @@
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/ceph/go-ceph v0.37.0 h1:KXliBe3ZDr3/AtfY7n9d1MG7ippYNCVhMPcAgm05CFI=
+github.com/ceph/go-ceph v0.37.0/go.mod h1:3y2tOlITlyuVFhy8v6PpCEfjMwKPfXJiH0/2hKZZQRE=
+github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
+github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
+github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
+github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
+github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
+github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
+github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
+github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
+github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
+go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
+go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
+go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
+go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
+go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
+golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
+google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/rbd_exporter/logger/logger.go b/rbd_exporter/logger/logger.go
new file mode 100644
index 0000000..956f0e0
--- /dev/null
+++ b/rbd_exporter/logger/logger.go
@@ -0,0 +1,10 @@
+package logger
+
+import "go.uber.org/zap"
+
+var Logger *zap.SugaredLogger
+
+// SetLogger is called from init()
+func SetLogger(l *zap.SugaredLogger) {
+ Logger = l
+}
\ No newline at end of file
diff --git a/rbd_exporter/main.go b/rbd_exporter/main.go
new file mode 100644
index 0000000..511cabe
--- /dev/null
+++ b/rbd_exporter/main.go
@@ -0,0 +1,81 @@
+package main
+
+import (
+ "errors"
+ "flag"
+ "fmt"
+ "net/http"
+ "os"
+ "rbd_exporter/mytypes"
+ "rbd_exporter/metrics"
+ "rbd_exporter/logger"
+ "rbd_exporter/connection"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+
+var params mytypes.Params
+var mainlogger *zap.SugaredLogger
+
+// Here I initialize logger
+func loggerInit() *zap.SugaredLogger {
+ config := zap.NewDevelopmentConfig()
+ config.EncoderConfig.TimeKey = "timestamp"
+ config.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
+ logger, err := config.Build()
+ if err != nil {
+ panic(fmt.Sprintf("Logger set up failed: %v", err))
+ }
+ defer logger.Sync()
+ return logger.Sugar()
+}
+
+// This func runs even before main()
+func init() {
+
+ config_file := flag.String("config", "/etc/ceph/ceph.conf", "placement of ceph config file")
+ _keyring := flag.String("keyring", "/etc/ceph/ceph.client.admin.keyring", "placement of ceph keyring file")
+ flag.Parse()
+
+ params.Config = *config_file
+ params.Keyring = *_keyring
+
+ mainlogger = loggerInit()
+ logger.SetLogger(mainlogger)
+ mainlogger.Info("Setting up logger is complete successfully")
+ mainlogger.Info("Registering prom metrics")
+}
+
+
+func main() {
+ cephConn, err := connection.Connect(params)
+ if err != nil {
+ fmt.Println(err)
+ if wrapped := errors.Unwrap(err); wrapped != nil {
+ fmt.Println(wrapped)
+ }
+ os.Exit(1)
+ }
+ defer cephConn.Conn.Shutdown()
+ mainlogger.Info("Successfully connected")
+
+ http.Handle("/metrics", promhttp.Handler())
+
+ // HTTP runs in separate thread cuz it blocks futher execution of main
+ go func() {
+ mainlogger.Info("Starting http server")
+ // Here I check for errors if HTTP fails
+ if err := http.ListenAndServe(":9040", nil); err != nil {
+ mainlogger.Fatalf("HTTP server failed to start %v", err)
+ }
+ mainlogger.Info("HTTP server started")
+ }()
+
+
+ go metrics.GetMetrics(cephConn)
+
+ select {}
+
+}
diff --git a/rbd_exporter/metrics/metrics.go b/rbd_exporter/metrics/metrics.go
new file mode 100644
index 0000000..ed9dee9
--- /dev/null
+++ b/rbd_exporter/metrics/metrics.go
@@ -0,0 +1,83 @@
+package metrics
+
+import (
+ "fmt"
+ "rbd_exporter/RBDFactory"
+ "rbd_exporter/mytypes"
+ "rbd_exporter/logger"
+ "time"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+
+func GetMetrics(cephConn mytypes.CephConnector) {
+
+ metrics := InitMetrics()
+ prometheus.MustRegister(
+ metrics.Total_rbd_requested_size_per_pool,
+ )
+
+ ticker := time.NewTicker(2 * time.Second)
+ defer ticker.Stop()
+
+ for range ticker.C {
+ var result []mytypes.Pool = []mytypes.Pool{}
+ poolList, err := cephConn.ListPools()
+ if err != nil {
+ logger.Logger.Error("Cannot get list of pools")
+ // do not exit but continue checking
+ continue
+ }
+
+ for _, v := range poolList {
+ x, _ := RBDFactory.PoolFactory(cephConn, v)
+ result = append(result, x)
+ }
+
+ metrics.Total_rbd_requested_size_per_pool.Reset()
+ for _,v := range result {
+ if !v.HasRBD {continue}
+ FillMetrics(v,metrics)
+ }
+ fmt.Println("====================")
+ // fmt.Println(result)
+
+ }
+}
+
+
+func InitMetrics() *mytypes.Metrics {
+ m := &mytypes.Metrics{
+ Total_rbd_requested_size_per_pool: prometheus.NewGaugeVec(
+ prometheus.GaugeOpts{
+ Name: "total_rbd_requested_size_per_pool",
+ Help: "total size of all requested RBDs in a specific pool",
+ },
+ []string{"poolname"},
+ ),
+
+ // total_rbd_requested_size: prometheus.NewGauge(
+ // prometheus.GaugeOpts{
+ // Name: "total_rbd_requested_size",
+ // Help: "total size of all RBDs in the cluster",
+ // },
+ // ),
+ }
+ return m
+}
+
+
+func FillMetrics(pool mytypes.Pool,metrics *mytypes.Metrics) {
+ var totalSizePerPool uint64 = 0
+
+ logger.Logger.Debugf("Processing pool %s",pool.Name)
+ for _,v := range pool.RBDlist {
+ totalSizePerPool += uint64(v.GetSize())
+ }
+ logger.Logger.Debugf("Total size of RBDs in pool %s is %d",pool.Name,totalSizePerPool)
+
+ metrics.Total_rbd_requested_size_per_pool.WithLabelValues(pool.Name,
+ ).Set(
+ float64(totalSizePerPool))
+
+}
\ No newline at end of file
diff --git a/rbd_exporter/mytypes/mock/types_mockgen_mock.go b/rbd_exporter/mytypes/mock/types_mockgen_mock.go
new file mode 100644
index 0000000..c87f213
--- /dev/null
+++ b/rbd_exporter/mytypes/mock/types_mockgen_mock.go
@@ -0,0 +1,256 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: mytypes/types.go
+//
+// Generated by this command:
+//
+// mockgen -source=mytypes/types.go -destination=mytypes/types_mockgen_mock.go -package=mocks
+//
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+ mytypes "rbd_exporter/mytypes"
+ reflect "reflect"
+
+ rbd "github.com/ceph/go-ceph/rbd"
+ gomock "go.uber.org/mock/gomock"
+)
+
+// MockCephConnector is a mock of CephConnector interface.
+type MockCephConnector struct {
+ ctrl *gomock.Controller
+ recorder *MockCephConnectorMockRecorder
+ isgomock struct{}
+}
+
+// MockCephConnectorMockRecorder is the mock recorder for MockCephConnector.
+type MockCephConnectorMockRecorder struct {
+ mock *MockCephConnector
+}
+
+// NewMockCephConnector creates a new mock instance.
+func NewMockCephConnector(ctrl *gomock.Controller) *MockCephConnector {
+ mock := &MockCephConnector{ctrl: ctrl}
+ mock.recorder = &MockCephConnectorMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockCephConnector) EXPECT() *MockCephConnectorMockRecorder {
+ return m.recorder
+}
+
+// ListPools mocks base method.
+func (m *MockCephConnector) ListPools() ([]string, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "ListPools")
+ ret0, _ := ret[0].([]string)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// ListPools indicates an expected call of ListPools.
+func (mr *MockCephConnectorMockRecorder) ListPools() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPools", reflect.TypeOf((*MockCephConnector)(nil).ListPools))
+}
+
+// OpenIOContext mocks base method.
+func (m *MockCephConnector) OpenIOContext(poolName string) (mytypes.IOContexter, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "OpenIOContext", poolName)
+ ret0, _ := ret[0].(mytypes.IOContexter)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// OpenIOContext indicates an expected call of OpenIOContext.
+func (mr *MockCephConnectorMockRecorder) OpenIOContext(poolName any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenIOContext", reflect.TypeOf((*MockCephConnector)(nil).OpenIOContext), poolName)
+}
+
+// MockIOContexter is a mock of IOContexter interface.
+type MockIOContexter struct {
+ ctrl *gomock.Controller
+ recorder *MockIOContexterMockRecorder
+ isgomock struct{}
+}
+
+// MockIOContexterMockRecorder is the mock recorder for MockIOContexter.
+type MockIOContexterMockRecorder struct {
+ mock *MockIOContexter
+}
+
+// NewMockIOContexter creates a new mock instance.
+func NewMockIOContexter(ctrl *gomock.Controller) *MockIOContexter {
+ mock := &MockIOContexter{ctrl: ctrl}
+ mock.recorder = &MockIOContexterMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockIOContexter) EXPECT() *MockIOContexterMockRecorder {
+ return m.recorder
+}
+
+// Destroy mocks base method.
+func (m *MockIOContexter) Destroy() {
+ m.ctrl.T.Helper()
+ m.ctrl.Call(m, "Destroy")
+}
+
+// Destroy indicates an expected call of Destroy.
+func (mr *MockIOContexterMockRecorder) Destroy() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Destroy", reflect.TypeOf((*MockIOContexter)(nil).Destroy))
+}
+
+// GetImage mocks base method.
+func (m *MockIOContexter) GetImage(name string) mytypes.RBDImager {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetImage", name)
+ ret0, _ := ret[0].(mytypes.RBDImager)
+ return ret0
+}
+
+// GetImage indicates an expected call of GetImage.
+func (mr *MockIOContexterMockRecorder) GetImage(name any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetImage", reflect.TypeOf((*MockIOContexter)(nil).GetImage), name)
+}
+
+// GetImageNames mocks base method.
+func (m *MockIOContexter) GetImageNames() ([]string, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetImageNames")
+ ret0, _ := ret[0].([]string)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// GetImageNames indicates an expected call of GetImageNames.
+func (mr *MockIOContexterMockRecorder) GetImageNames() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetImageNames", reflect.TypeOf((*MockIOContexter)(nil).GetImageNames))
+}
+
+// MockRBDImager is a mock of RBDImager interface.
+type MockRBDImager struct {
+ ctrl *gomock.Controller
+ recorder *MockRBDImagerMockRecorder
+ isgomock struct{}
+}
+
+// MockRBDImagerMockRecorder is the mock recorder for MockRBDImager.
+type MockRBDImagerMockRecorder struct {
+ mock *MockRBDImager
+}
+
+// NewMockRBDImager creates a new mock instance.
+func NewMockRBDImager(ctrl *gomock.Controller) *MockRBDImager {
+ mock := &MockRBDImager{ctrl: ctrl}
+ mock.recorder = &MockRBDImagerMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockRBDImager) EXPECT() *MockRBDImagerMockRecorder {
+ return m.recorder
+}
+
+// Close mocks base method.
+func (m *MockRBDImager) Close() error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Close")
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// Close indicates an expected call of Close.
+func (mr *MockRBDImagerMockRecorder) Close() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockRBDImager)(nil).Close))
+}
+
+// Open mocks base method.
+func (m *MockRBDImager) Open() error {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Open")
+ ret0, _ := ret[0].(error)
+ return ret0
+}
+
+// Open indicates an expected call of Open.
+func (mr *MockRBDImagerMockRecorder) Open() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Open", reflect.TypeOf((*MockRBDImager)(nil).Open))
+}
+
+// Stat mocks base method.
+func (m *MockRBDImager) Stat() (*rbd.ImageInfo, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "Stat")
+ ret0, _ := ret[0].(*rbd.ImageInfo)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// Stat indicates an expected call of Stat.
+func (mr *MockRBDImagerMockRecorder) Stat() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Stat", reflect.TypeOf((*MockRBDImager)(nil).Stat))
+}
+
+// MockIRBD is a mock of IRBD interface.
+type MockIRBD struct {
+ ctrl *gomock.Controller
+ recorder *MockIRBDMockRecorder
+ isgomock struct{}
+}
+
+// MockIRBDMockRecorder is the mock recorder for MockIRBD.
+type MockIRBDMockRecorder struct {
+ mock *MockIRBD
+}
+
+// NewMockIRBD creates a new mock instance.
+func NewMockIRBD(ctrl *gomock.Controller) *MockIRBD {
+ mock := &MockIRBD{ctrl: ctrl}
+ mock.recorder = &MockIRBDMockRecorder{mock}
+ return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockIRBD) EXPECT() *MockIRBDMockRecorder {
+ return m.recorder
+}
+
+// GetName mocks base method.
+func (m *MockIRBD) GetName() string {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetName")
+ ret0, _ := ret[0].(string)
+ return ret0
+}
+
+// GetName indicates an expected call of GetName.
+func (mr *MockIRBDMockRecorder) GetName() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetName", reflect.TypeOf((*MockIRBD)(nil).GetName))
+}
+
+// GetSize mocks base method.
+func (m *MockIRBD) GetSize() int64 {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "GetSize")
+ ret0, _ := ret[0].(int64)
+ return ret0
+}
+
+// GetSize indicates an expected call of GetSize.
+func (mr *MockIRBDMockRecorder) GetSize() *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSize", reflect.TypeOf((*MockIRBD)(nil).GetSize))
+}
diff --git a/rbd_exporter/mytypes/types.go b/rbd_exporter/mytypes/types.go
new file mode 100644
index 0000000..68af6e8
--- /dev/null
+++ b/rbd_exporter/mytypes/types.go
@@ -0,0 +1,115 @@
+package mytypes
+
+import (
+ "github.com/ceph/go-ceph/rados"
+ "github.com/ceph/go-ceph/rbd"
+ "github.com/prometheus/client_golang/prometheus"
+)
+
+type Params struct {
+ Config string
+ Keyring string
+}
+
+type CephConnector interface {
+ ListPools() ([]string,error)
+ OpenIOContext(poolName string) (IOContexter, error)
+}
+
+type CephConnection struct {
+ Conn *rados.Conn
+}
+
+// Here I do implement CephConnector interface
+func (cc CephConnection) ListPools() ([]string,error) {
+ return cc.Conn.ListPools()
+}
+
+// Here I do implement CephConnector interface
+func (cc CephConnection) OpenIOContext(poolName string) (IOContexter,error) {
+ ioctx,err := cc.Conn.OpenIOContext(poolName)
+ if err != nil {
+ return nil,err
+ }
+ return IOContextWrapper{ioctx: ioctx},nil
+}
+
+
+type IOContexter interface {
+ Destroy()
+ GetImageNames() ([]string, error)
+ GetImage(name string) RBDImager
+}
+
+type IOContextWrapper struct {
+ ioctx *rados.IOContext
+}
+
+func (iocw IOContextWrapper) Destroy() {
+ iocw.ioctx.Destroy()
+}
+
+func (iocw IOContextWrapper) GetImageNames() ([]string,error){
+ return rbd.GetImageNames(iocw.ioctx)
+}
+
+func (iocw IOContextWrapper) GetImage(rbdName string) RBDImager {
+ img := rbd.GetImage(iocw.ioctx,rbdName)
+ return RBDImageWrapper{image: img}
+}
+
+
+type RBDImager interface {
+ Open() error
+ Close() error
+ Stat() (*rbd.ImageInfo,error)
+}
+
+type RBDImageWrapper struct {
+ image *rbd.Image
+}
+
+func (riw RBDImageWrapper) Open() error {
+ return riw.image.Open()
+}
+
+func (riw RBDImageWrapper) Close() error {
+ return riw.image.Close()
+}
+
+func (riw RBDImageWrapper) Stat() (*rbd.ImageInfo,error) {
+ return riw.image.Stat()
+}
+
+type IRBD interface {
+ GetName() string
+ GetSize() int64
+}
+
+type RBDUsage struct {
+ Images []RBD
+}
+
+type RBD struct {
+ Name string
+ rbd.ImageInfo
+}
+
+func (r RBD) GetName() string {
+ return r.Name
+}
+
+func (r RBD) GetSize() int64 {
+ return int64(r.Size)
+}
+
+type Pool struct {
+ Name string
+ HasRBD bool
+ RBDlist []IRBD
+}
+
+type Metrics struct {
+ Total_rbd_requested_size_per_pool *prometheus.GaugeVec
+ Total_rbd_requested_size prometheus.Gauge
+}
diff --git a/rbd_exporter/tests/RBDFactory_test.go b/rbd_exporter/tests/RBDFactory_test.go
new file mode 100644
index 0000000..b30f3b2
--- /dev/null
+++ b/rbd_exporter/tests/RBDFactory_test.go
@@ -0,0 +1,73 @@
+package tests
+
+import (
+ "rbd_exporter/RBDFactory"
+ mock "rbd_exporter/mytypes/mock"
+ "testing"
+
+ "github.com/ceph/go-ceph/rbd"
+ gomock "go.uber.org/mock/gomock"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+
+func TestRBDFactory(t *testing.T) {
+ mockCtrl := gomock.NewController(t)
+ defer mockCtrl.Finish()
+
+ MockIOContexter := mock.NewMockIOContexter(mockCtrl)
+ MockRBDImager := mock.NewMockRBDImager(mockCtrl)
+
+ rbdName := "test-rbd"
+ expectedImageInfo := &rbd.ImageInfo{
+ Size: 1488,
+ }
+
+ MockIOContexter.EXPECT().GetImage(rbdName).Return(MockRBDImager)
+ MockRBDImager.EXPECT().Open().Return(nil)
+ MockRBDImager.EXPECT().Close().Return(nil)
+ MockRBDImager.EXPECT().Stat().Return(expectedImageInfo,nil)
+
+
+ result,err := RBDFactory.RBDFacroty(MockIOContexter,rbdName)
+
+ require.NoError(t, err)
+ assert.Equal(t, rbdName, result.Name)
+ assert.Equal(t, expectedImageInfo.Size, result.ImageInfo.Size)
+}
+
+
+func TestPoolFactory(t *testing.T) {
+ mockCtrl := gomock.NewController(t)
+ defer mockCtrl.Finish()
+
+ mockCephConn := mock.NewMockCephConnector(mockCtrl)
+ mockIOCtx := mock.NewMockIOContexter(mockCtrl)
+ mockImage := mock.NewMockRBDImager(mockCtrl)
+
+
+ poolName := "test-pool"
+ imageNames := []string{"rbd1", "rbd2"}
+ expectedImageInfo := &rbd.ImageInfo{Size: 1024}
+
+ mockCephConn.EXPECT().OpenIOContext(poolName).Return(mockIOCtx,nil)
+ mockIOCtx.EXPECT().GetImageNames().Return(imageNames,nil)
+ mockIOCtx.EXPECT().Destroy()
+
+ for _, imageName := range imageNames {
+ mockIOCtx.EXPECT().GetImage(imageName).Return(mockImage)
+ mockImage.EXPECT().Open().Return(nil)
+ mockImage.EXPECT().Close().Return(nil)
+ mockImage.EXPECT().Stat().Return(expectedImageInfo, nil)
+ }
+
+ result, err := RBDFactory.PoolFactory(mockCephConn, poolName)
+
+ require.NoError(t, err)
+ assert.Equal(t, poolName, result.Name)
+ assert.True(t, result.HasRBD)
+ assert.Len(t, result.RBDlist, 2)
+ assert.Equal(t, "rbd1", result.RBDlist[0].GetName())
+ assert.Equal(t, "rbd2", result.RBDlist[1].GetName())
+}
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/.gitignore b/testing/go-code-samples/mock-testing/fetchuser/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/fetchuser.iml b/testing/go-code-samples/mock-testing/fetchuser/.idea/fetchuser.iml
deleted file mode 100644
index 7ee078d..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/fetchuser.iml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_All.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_All.xml
deleted file mode 100644
index e5cb9a1..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_All.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_HigherOrderFunctions.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_HigherOrderFunctions.xml
deleted file mode 100644
index 2f0e715..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_HigherOrderFunctions.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_HttpTest.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_HttpTest.xml
deleted file mode 100644
index 95b6f6e..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_HttpTest.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_InterfaceMock1.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_InterfaceMock1.xml
deleted file mode 100644
index 84b46fd..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_InterfaceMock1.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_InterfaceMock2.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_InterfaceMock2.xml
deleted file mode 100644
index 8356b43..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_InterfaceMock2.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_Mockgen.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_Mockgen.xml
deleted file mode 100644
index 6995d67..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_Mockgen.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_TestifyMock.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_TestifyMock.xml
deleted file mode 100644
index f31bb64..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/runConfigurations/TestProcessUser_TestifyMock.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/.idea/vcs.xml b/testing/go-code-samples/mock-testing/fetchuser/.idea/vcs.xml
deleted file mode 100644
index b2bdec2..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/testing/go-code-samples/mock-testing/fetchuser/fetchuser_mockgen_mocks.go b/testing/go-code-samples/mock-testing/fetchuser/fetchuser_mockgen_mocks.go
index 47422fc..46678ba 100644
--- a/testing/go-code-samples/mock-testing/fetchuser/fetchuser_mockgen_mocks.go
+++ b/testing/go-code-samples/mock-testing/fetchuser/fetchuser_mockgen_mocks.go
@@ -1,5 +1,10 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: fetchuser.go
+//
+// Generated by this command:
+//
+// mockgen -source=fetchuser.go -destination=fetchuser_mockgen_mocks.go -package=fetchuser
+//
// Package fetchuser is a generated GoMock package.
package fetchuser
@@ -14,6 +19,7 @@ import (
type MockAPIFetcher struct {
ctrl *gomock.Controller
recorder *MockAPIFetcherMockRecorder
+ isgomock struct{}
}
// MockAPIFetcherMockRecorder is the mock recorder for MockAPIFetcher.
@@ -43,7 +49,7 @@ func (m *MockAPIFetcher) FetchData(id int) (User, error) {
}
// FetchData indicates an expected call of FetchData.
-func (mr *MockAPIFetcherMockRecorder) FetchData(id interface{}) *gomock.Call {
+func (mr *MockAPIFetcherMockRecorder) FetchData(id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FetchData", reflect.TypeOf((*MockAPIFetcher)(nil).FetchData), id)
}
diff --git a/testing/go-code-samples/mock-testing/fetchuser/fetchuser_mockgen_test.go b/testing/go-code-samples/mock-testing/fetchuser/fetchuser_mockgen_test.go
deleted file mode 100644
index fd7ed43..0000000
--- a/testing/go-code-samples/mock-testing/fetchuser/fetchuser_mockgen_test.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package fetchuser
-
-import (
- "testing"
-
- "go.uber.org/mock/gomock"
-)
-
-func TestProcessUser_Mockgen(t *testing.T) {
- ctrl := gomock.NewController(t)
- defer ctrl.Finish()
-
- user := User{ID: 1, Name: "Alice"}
- mockFetcher := NewMockAPIFetcher(ctrl)
- mockFetcher.EXPECT().FetchData(1).Return(user, nil)
-
- result, err := ProcessUser(mockFetcher, 1)
- if err != nil {
- t.Errorf("unexpected error: %v", err)
- }
-
- if result != user {
- t.Errorf("expected user: %v, got: %v", user, result)
- }
-}
diff --git a/testing/go-code-samples/mock-testing/fetchuser/go.mod b/testing/go-code-samples/mock-testing/fetchuser/go.mod
index b941b01..6587c17 100644
--- a/testing/go-code-samples/mock-testing/fetchuser/go.mod
+++ b/testing/go-code-samples/mock-testing/fetchuser/go.mod
@@ -1,15 +1,15 @@
-module github.com/JetBrains/go-code-samples/mock-testing/fetchuser
+module fetcher
-go 1.20
+go 1.25.5
require (
- github.com/stretchr/testify v1.8.4
- go.uber.org/mock v0.2.0
+ github.com/stretchr/testify v1.11.1
+ go.uber.org/mock v0.6.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/stretchr/objx v0.5.0 // indirect
+ github.com/stretchr/objx v0.5.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/testing/go-code-samples/mock-testing/fetchuser/go.sum b/testing/go-code-samples/mock-testing/fetchuser/go.sum
index 7b5f618..ff1eeb2 100644
--- a/testing/go-code-samples/mock-testing/fetchuser/go.sum
+++ b/testing/go-code-samples/mock-testing/fetchuser/go.sum
@@ -1,20 +1,39 @@
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
+github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
-go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
+go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/testing/go-code-samples/mock-testing/fetchuser/test_fetchuser.go b/testing/go-code-samples/mock-testing/fetchuser/test_fetchuser.go
new file mode 100644
index 0000000..e70244d
--- /dev/null
+++ b/testing/go-code-samples/mock-testing/fetchuser/test_fetchuser.go
@@ -0,0 +1,25 @@
+package fetchuser
+
+import (
+ "testing"
+
+ gomock "go.uber.org/mock/gomock")
+
+func TestProcessUser_Mockgen(t *testing.T) {
+ ctrl := gomock.NewController(t)
+ defer ctrl.Finish()
+
+ user := User{ID: 1, Name: "Alice"}
+
+ mockFetcher := NewMockAPIFetcher(ctrl)
+ mockFetcher.EXPECT().FetchData(1).Return(user, nil)
+
+ result, err := ProcessUser(mockFetcher, 1)
+ if err != nil {
+ t.Errorf("unexpected error: %v", err)
+ }
+
+ if result != user {
+ t.Errorf("expected user: %v, got: %v", user, result)
+ }
+}