mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-11 21:51:21 +00:00
Added security checks & server storage engine
This commit is contained in:
@@ -60,6 +60,16 @@ type Security struct {
|
|||||||
type Net struct {
|
type Net struct {
|
||||||
HTTP HTTP `bson:"http"`
|
HTTP HTTP `bson:"http"`
|
||||||
SSL SSL `bson:"ssl"`
|
SSL SSL `bson:"ssl"`
|
||||||
|
Port int64 `bson:"port"`
|
||||||
|
BindIP string `bson:"bindIp"`
|
||||||
|
MaxIncomingConnections int `bson:"maxIncomingConnections"`
|
||||||
|
WireObjectCheck bool `bson:"wireObjectCheck"`
|
||||||
|
IPv6 bool `bson:"ipv6"`
|
||||||
|
UnixDomainSocket struct {
|
||||||
|
Enabled bool `bson:"enabled"`
|
||||||
|
PathPrefix string `bson:"pathPrefix"`
|
||||||
|
FilePermissions int64 `bson:"filePermissions"`
|
||||||
|
} `bson:"unixDomainSocket"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type HTTP struct {
|
type HTTP struct {
|
||||||
|
@@ -20,6 +20,7 @@ type Members struct {
|
|||||||
ElectionTime int64 `bson:"electionTime"` // For the current primary, information regarding the election Timestamp from the operation log.
|
ElectionTime int64 `bson:"electionTime"` // For the current primary, information regarding the election Timestamp from the operation log.
|
||||||
ElectionDate string `bson:"electionDate"` // For the current primary, an ISODate formatted date string that reflects the election date
|
ElectionDate string `bson:"electionDate"` // For the current primary, an ISODate formatted date string that reflects the election date
|
||||||
Set string `bson:"-"`
|
Set string `bson:"-"`
|
||||||
|
StorageEngine StorageEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
// Struct for replSetGetStatus
|
// Struct for replSetGetStatus
|
||||||
|
@@ -25,10 +25,17 @@ type ServerStatus struct {
|
|||||||
Mem *MemStats `bson:"mem"`
|
Mem *MemStats `bson:"mem"`
|
||||||
Repl *ReplStatus `bson:"repl"`
|
Repl *ReplStatus `bson:"repl"`
|
||||||
ShardCursorType map[string]interface{} `bson:"shardCursorType"`
|
ShardCursorType map[string]interface{} `bson:"shardCursorType"`
|
||||||
StorageEngine map[string]string `bson:"storageEngine"`
|
StorageEngine StorageEngine `bson:"storageEngine"`
|
||||||
WiredTiger *WiredTiger `bson:"wiredTiger"`
|
WiredTiger *WiredTiger `bson:"wiredTiger"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type StorageEngine struct {
|
||||||
|
Name string `bson:"name"`
|
||||||
|
SupportCommittedREads bool `bson:supportsCommittedReads"`
|
||||||
|
ReadOnly bool `bson:"readOnly"`
|
||||||
|
Persistent bool `bson:"persistent"`
|
||||||
|
}
|
||||||
|
|
||||||
// WiredTiger stores information related to the WiredTiger storage engine.
|
// WiredTiger stores information related to the WiredTiger storage engine.
|
||||||
type WiredTiger struct {
|
type WiredTiger struct {
|
||||||
Transaction TransactionStats `bson:"transaction"`
|
Transaction TransactionStats `bson:"transaction"`
|
||||||
|
@@ -2,11 +2,13 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
version "github.com/hashicorp/go-version"
|
||||||
"github.com/howeyc/gopass"
|
"github.com/howeyc/gopass"
|
||||||
"github.com/pborman/getopt"
|
"github.com/pborman/getopt"
|
||||||
"github.com/percona/percona-toolkit/src/go/lib/config"
|
"github.com/percona/percona-toolkit/src/go/lib/config"
|
||||||
@@ -82,6 +84,9 @@ type security struct {
|
|||||||
Roles int
|
Roles int
|
||||||
Auth string
|
Auth string
|
||||||
SSL string
|
SSL string
|
||||||
|
BindIP string
|
||||||
|
Port int64
|
||||||
|
WarningMsgs []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type databases struct {
|
type databases struct {
|
||||||
@@ -209,7 +214,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
if hostInfo, err := GetHostinfo(session); err != nil {
|
|
||||||
|
hostInfo, err := GetHostinfo(session)
|
||||||
|
if err != nil {
|
||||||
log.Printf("[Error] cannot get host info: %v\n", err)
|
log.Printf("[Error] cannot get host info: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("hostInfo:\n%+v\n", hostInfo)
|
log.Debugf("hostInfo:\n%+v\n", hostInfo)
|
||||||
@@ -226,7 +233,7 @@ func main() {
|
|||||||
t.Execute(os.Stdout, rops)
|
t.Execute(os.Stdout, rops)
|
||||||
}
|
}
|
||||||
|
|
||||||
if security, err := GetSecuritySettings(session); err != nil {
|
if security, err := GetSecuritySettings(session, hostInfo.Version); err != nil {
|
||||||
log.Printf("[Error] cannot get security settings: %v\n", err)
|
log.Printf("[Error] cannot get security settings: %v\n", err)
|
||||||
} else {
|
} else {
|
||||||
t := template.Must(template.New("ssl").Parse(templates.Security))
|
t := template.Must(template.New("ssl").Parse(templates.Security))
|
||||||
@@ -396,13 +403,14 @@ func GetReplicasetMembers(dialer pmgo.Dialer, hostnames []string, di *mgo.DialIn
|
|||||||
log.Debugf("hostnames: %+v", hostnames)
|
log.Debugf("hostnames: %+v", hostnames)
|
||||||
|
|
||||||
for _, hostname := range hostnames {
|
for _, hostname := range hostnames {
|
||||||
di.Addrs = []string{hostname}
|
tmpdi := *di
|
||||||
session, err := dialer.DialWithInfo(di)
|
tmpdi.Addrs = []string{hostname}
|
||||||
|
log.Debugf("GetReplicasetMembers connecting to %s", hostname)
|
||||||
|
session, err := dialer.DialWithInfo(&tmpdi)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debugf("getReplicasetMembers. cannot connect to %s: %s", hostname, err.Error())
|
log.Debugf("getReplicasetMembers. cannot connect to %s: %s", hostname, err.Error())
|
||||||
return nil, errors.Wrapf(err, "getReplicasetMembers. cannot connect to %s", hostname)
|
return nil, errors.Wrapf(err, "getReplicasetMembers. cannot connect to %s", hostname)
|
||||||
}
|
}
|
||||||
defer session.Close()
|
|
||||||
|
|
||||||
rss := proto.ReplicaSetStatus{}
|
rss := proto.ReplicaSetStatus{}
|
||||||
err = session.Run(bson.M{"replSetGetStatus": 1}, &rss)
|
err = session.Run(bson.M{"replSetGetStatus": 1}, &rss)
|
||||||
@@ -413,21 +421,55 @@ func GetReplicasetMembers(dialer pmgo.Dialer, hostnames []string, di *mgo.DialIn
|
|||||||
log.Debugf("replSetGetStatus result:\n%#v", rss)
|
log.Debugf("replSetGetStatus result:\n%#v", rss)
|
||||||
for _, m := range rss.Members {
|
for _, m := range rss.Members {
|
||||||
m.Set = rss.Set
|
m.Set = rss.Set
|
||||||
|
if serverStatus, err := getServerStatus(dialer, di, m.Name); err == nil {
|
||||||
|
m.StorageEngine = serverStatus.StorageEngine
|
||||||
|
} else {
|
||||||
|
log.Warnf("getReplicasetMembers. cannot get server status: %v", err.Error())
|
||||||
|
}
|
||||||
replicaMembers = append(replicaMembers, m)
|
replicaMembers = append(replicaMembers, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
return replicaMembers, nil
|
return replicaMembers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSecuritySettings(session pmgo.SessionManager) (*security, error) {
|
func getServerStatus(dialer pmgo.Dialer, di *mgo.DialInfo, hostname string) (proto.ServerStatus, error) {
|
||||||
|
ss := proto.ServerStatus{}
|
||||||
|
|
||||||
|
tmpdi := *di
|
||||||
|
tmpdi.Addrs = []string{hostname}
|
||||||
|
log.Debugf("GetReplicasetMembers connecting to %s", hostname)
|
||||||
|
|
||||||
|
session, err := dialer.DialWithInfo(&tmpdi)
|
||||||
|
if err != nil {
|
||||||
|
return ss, errors.Wrapf(err, "getReplicasetMembers. cannot connect to %s", hostname)
|
||||||
|
}
|
||||||
|
defer session.Close()
|
||||||
|
|
||||||
|
if err := session.DB("admin").Run(bson.D{{"serverStatus", 1}, {"recordStats", 1}}, &ss); err != nil {
|
||||||
|
return ss, errors.Wrap(err, "GetHostInfo.serverStatus")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetSecuritySettings(session pmgo.SessionManager, ver string) (*security, error) {
|
||||||
s := security{
|
s := security{
|
||||||
Auth: "disabled",
|
Auth: "disabled",
|
||||||
SSL: "disabled",
|
SSL: "disabled",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v26, _ := version.NewVersion("2.6")
|
||||||
|
mongoVersion, err := version.NewVersion(ver)
|
||||||
|
prior26 := false
|
||||||
|
if err == nil && mongoVersion.LessThan(v26) {
|
||||||
|
prior26 = true
|
||||||
|
}
|
||||||
|
|
||||||
cmdOpts := proto.CommandLineOptions{}
|
cmdOpts := proto.CommandLineOptions{}
|
||||||
err := session.DB("admin").Run(bson.D{{"getCmdLineOpts", 1}, {"recordStats", 1}}, &cmdOpts)
|
err = session.DB("admin").Run(bson.D{{"getCmdLineOpts", 1}, {"recordStats", 1}}, &cmdOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot get command line options")
|
return nil, errors.Wrap(err, "cannot get command line options")
|
||||||
}
|
}
|
||||||
@@ -435,10 +477,37 @@ func GetSecuritySettings(session pmgo.SessionManager) (*security, error) {
|
|||||||
if cmdOpts.Security.Authorization != "" || cmdOpts.Security.KeyFile != "" {
|
if cmdOpts.Security.Authorization != "" || cmdOpts.Security.KeyFile != "" {
|
||||||
s.Auth = "enabled"
|
s.Auth = "enabled"
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmdOpts.Parsed.Net.SSL.Mode != "" && cmdOpts.Parsed.Net.SSL.Mode != "disabled" {
|
if cmdOpts.Parsed.Net.SSL.Mode != "" && cmdOpts.Parsed.Net.SSL.Mode != "disabled" {
|
||||||
s.SSL = cmdOpts.Parsed.Net.SSL.Mode
|
s.SSL = cmdOpts.Parsed.Net.SSL.Mode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.BindIP = cmdOpts.Parsed.Net.BindIP
|
||||||
|
s.Port = cmdOpts.Parsed.Net.Port
|
||||||
|
|
||||||
|
if cmdOpts.Parsed.Net.BindIP == "" {
|
||||||
|
if prior26 {
|
||||||
|
s.WarningMsgs = append(s.WarningMsgs, "WARNING: You might be insecure. There is no IP binding")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ips := strings.Split(cmdOpts.Parsed.Net.BindIP, ",")
|
||||||
|
extIP, _ := externalIP()
|
||||||
|
for _, ip := range ips {
|
||||||
|
isPrivate, err := isPrivateNetwork(strings.TrimSpace(ip))
|
||||||
|
if !isPrivate && err == nil {
|
||||||
|
if s.Auth == "enabled" {
|
||||||
|
s.WarningMsgs = append(s.WarningMsgs, fmt.Sprintf("Warning: You might be insecure (bind ip %s is public)", ip))
|
||||||
|
} else {
|
||||||
|
s.WarningMsgs = append(s.WarningMsgs, fmt.Sprintf("Error. You are insecure: bind ip %s is public and auth is disabled", ip))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ip != "127.0.0.1" && ip != extIP {
|
||||||
|
s.WarningMsgs = append(s.WarningMsgs, fmt.Sprintf("WARNING: You might be insecure. IP binding %s is not localhost"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
s.Users, err = session.DB("admin").C("system.users").Count()
|
s.Users, err = session.DB("admin").C("system.users").Count()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot get users count")
|
return nil, errors.Wrap(err, "cannot get users count")
|
||||||
@@ -698,3 +767,62 @@ func GetShardingChangelogStatus(session pmgo.SessionManager) (*proto.ShardingCha
|
|||||||
Items: &qresults,
|
Items: &qresults,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isPrivateNetwork(ip string) (bool, error) {
|
||||||
|
privateCIDRs := []string{"10.0.0.0/24", "172.16.0.0/20", "192.168.0.0/16"}
|
||||||
|
|
||||||
|
if net.ParseIP(ip).String() == "127.0.0.1" {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, cidr := range privateCIDRs {
|
||||||
|
_, cidrnet, err := net.ParseCIDR(cidr)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
addr := net.ParseIP(ip)
|
||||||
|
if cidrnet.Contains(addr) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func externalIP() (string, error) {
|
||||||
|
ifaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, iface := range ifaces {
|
||||||
|
if iface.Flags&net.FlagUp == 0 {
|
||||||
|
continue // interface down
|
||||||
|
}
|
||||||
|
if iface.Flags&net.FlagLoopback != 0 {
|
||||||
|
continue // loopback interface
|
||||||
|
}
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
var ip net.IP
|
||||||
|
switch v := addr.(type) {
|
||||||
|
case *net.IPNet:
|
||||||
|
ip = v.IP
|
||||||
|
case *net.IPAddr:
|
||||||
|
ip = v.IP
|
||||||
|
}
|
||||||
|
if ip == nil || ip.IsLoopback() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ip = ip.To4()
|
||||||
|
if ip == nil {
|
||||||
|
continue // not an ipv4 address
|
||||||
|
}
|
||||||
|
return ip.String(), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errors.New("are you connected to the network?")
|
||||||
|
}
|
||||||
|
@@ -126,6 +126,9 @@ func TestSecurityOpts(t *testing.T) {
|
|||||||
Roles: 2,
|
Roles: 2,
|
||||||
Auth: "disabled",
|
Auth: "disabled",
|
||||||
SSL: "disabled",
|
SSL: "disabled",
|
||||||
|
BindIP: "",
|
||||||
|
Port: 0,
|
||||||
|
WarningMsgs: nil,
|
||||||
},
|
},
|
||||||
// 2
|
// 2
|
||||||
&security{
|
&security{
|
||||||
@@ -133,6 +136,8 @@ func TestSecurityOpts(t *testing.T) {
|
|||||||
Roles: 2,
|
Roles: 2,
|
||||||
Auth: "enabled",
|
Auth: "enabled",
|
||||||
SSL: "disabled",
|
SSL: "disabled",
|
||||||
|
BindIP: "", Port: 0,
|
||||||
|
WarningMsgs: nil,
|
||||||
},
|
},
|
||||||
// 3
|
// 3
|
||||||
&security{
|
&security{
|
||||||
@@ -140,6 +145,9 @@ func TestSecurityOpts(t *testing.T) {
|
|||||||
Roles: 2,
|
Roles: 2,
|
||||||
Auth: "enabled",
|
Auth: "enabled",
|
||||||
SSL: "disabled",
|
SSL: "disabled",
|
||||||
|
BindIP: "",
|
||||||
|
Port: 0,
|
||||||
|
WarningMsgs: nil,
|
||||||
},
|
},
|
||||||
// 4
|
// 4
|
||||||
&security{
|
&security{
|
||||||
@@ -147,6 +155,9 @@ func TestSecurityOpts(t *testing.T) {
|
|||||||
Roles: 2,
|
Roles: 2,
|
||||||
Auth: "disabled",
|
Auth: "disabled",
|
||||||
SSL: "super secure",
|
SSL: "super secure",
|
||||||
|
BindIP: "",
|
||||||
|
Port: 0,
|
||||||
|
WarningMsgs: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,13 +182,13 @@ func TestSecurityOpts(t *testing.T) {
|
|||||||
database.EXPECT().C("system.roles").Return(rolesCol)
|
database.EXPECT().C("system.roles").Return(rolesCol)
|
||||||
rolesCol.EXPECT().Count().Return(2, nil)
|
rolesCol.EXPECT().Count().Return(2, nil)
|
||||||
|
|
||||||
got, err := GetSecuritySettings(session)
|
got, err := GetSecuritySettings(session, "3.2")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("cannot get sec settings: %v", err)
|
t.Errorf("cannot get sec settings: %v", err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(got, expect[i]) {
|
if !reflect.DeepEqual(got, expect[i]) {
|
||||||
t.Errorf("got: %+v, expect: %+v\n", got, expect[i])
|
t.Errorf("got: %#v\nwant: %#v\n", got, expect[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,8 +336,28 @@ func TestGetReplicasetMembers(t *testing.T) {
|
|||||||
Set: "r1",
|
Set: "r1",
|
||||||
}}
|
}}
|
||||||
|
|
||||||
|
database := pmgomock.NewMockDatabaseManager(ctrl)
|
||||||
|
ss := proto.ServerStatus{}
|
||||||
|
test.LoadJson("test/sample/serverstatus.json", &ss)
|
||||||
|
|
||||||
dialer.EXPECT().DialWithInfo(gomock.Any()).Return(session, nil)
|
dialer.EXPECT().DialWithInfo(gomock.Any()).Return(session, nil)
|
||||||
session.EXPECT().Run(bson.M{"replSetGetStatus": 1}, gomock.Any()).SetArg(1, mockrss)
|
session.EXPECT().Run(bson.M{"replSetGetStatus": 1}, gomock.Any()).SetArg(1, mockrss)
|
||||||
|
|
||||||
|
dialer.EXPECT().DialWithInfo(gomock.Any()).Return(session, nil)
|
||||||
|
session.EXPECT().DB("admin").Return(database)
|
||||||
|
database.EXPECT().Run(bson.D{{"serverStatus", 1}, {"recordStats", 1}}, gomock.Any()).SetArg(1, ss)
|
||||||
|
session.EXPECT().Close()
|
||||||
|
|
||||||
|
dialer.EXPECT().DialWithInfo(gomock.Any()).Return(session, nil)
|
||||||
|
session.EXPECT().DB("admin").Return(database)
|
||||||
|
database.EXPECT().Run(bson.D{{"serverStatus", 1}, {"recordStats", 1}}, gomock.Any()).SetArg(1, ss)
|
||||||
|
session.EXPECT().Close()
|
||||||
|
|
||||||
|
dialer.EXPECT().DialWithInfo(gomock.Any()).Return(session, nil)
|
||||||
|
session.EXPECT().DB("admin").Return(database)
|
||||||
|
database.EXPECT().Run(bson.D{{"serverStatus", 1}, {"recordStats", 1}}, gomock.Any()).SetArg(1, ss)
|
||||||
|
session.EXPECT().Close()
|
||||||
|
|
||||||
session.EXPECT().Close()
|
session.EXPECT().Close()
|
||||||
|
|
||||||
di := &mgo.DialInfo{Addrs: []string{"localhost"}}
|
di := &mgo.DialInfo{Addrs: []string{"localhost"}}
|
||||||
@@ -335,7 +366,7 @@ func TestGetReplicasetMembers(t *testing.T) {
|
|||||||
t.Errorf("getReplicasetMembers: %v", err)
|
t.Errorf("getReplicasetMembers: %v", err)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(rss, expect) {
|
if !reflect.DeepEqual(rss, expect) {
|
||||||
t.Errorf("getReplicasetMembers: got %+v, expected: %+v\n", rss, expect)
|
t.Errorf("getReplicasetMembers:\ngot %#v\nwant: %#v\n", rss, expect)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -376,6 +407,58 @@ func TestGetHostnames(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsPrivateNetwork(t *testing.T) {
|
||||||
|
//privateCIDRs := []string{"10.0.0.0/24", "172.16.0.0/20", "192.168.0.0/16"}
|
||||||
|
testdata :=
|
||||||
|
[]struct {
|
||||||
|
ip string
|
||||||
|
want bool
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
ip: "127.0.0.1",
|
||||||
|
want: true,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ip: "10.0.0.1",
|
||||||
|
want: true,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ip: "10.0.1.1",
|
||||||
|
want: false,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ip: "172.16.1.2",
|
||||||
|
want: true,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ip: "192.168.1.2",
|
||||||
|
want: true,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ip: "8.8.8.8",
|
||||||
|
want: false,
|
||||||
|
err: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, in := range testdata {
|
||||||
|
got, err := isPrivateNetwork(in.ip)
|
||||||
|
if err != in.err {
|
||||||
|
t.Errorf("ip %s. got err: %s, want err: %v", in.ip, err, in.err)
|
||||||
|
}
|
||||||
|
if got != in.want {
|
||||||
|
t.Errorf("ip %s. got: %v, want : %v", in.ip, got, in.want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func addToCounters(ss proto.ServerStatus, increment int64) proto.ServerStatus {
|
func addToCounters(ss proto.ServerStatus, increment int64) proto.ServerStatus {
|
||||||
ss.Opcounters.Command += increment
|
ss.Opcounters.Command += increment
|
||||||
ss.Opcounters.Delete += increment
|
ss.Opcounters.Delete += increment
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
const Clusterwide = `
|
const Clusterwide = `
|
||||||
# Cluster wide #################################################################################
|
# Cluster wide ###########################################################################################
|
||||||
Databases: {{.TotalDBsCount}}
|
Databases: {{.TotalDBsCount}}
|
||||||
Collections: {{.TotalCollectionsCount}}
|
Collections: {{.TotalCollectionsCount}}
|
||||||
Sharded Collections: {{.ShardedColsCount}}
|
Sharded Collections: {{.ShardedColsCount}}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
const HostInfo = `# This host
|
const HostInfo = `# This host
|
||||||
# Mongo Executable #############################################################################
|
# Mongo Executable #######################################################################################
|
||||||
Path to executable | {{.ProcPath}}
|
Path to executable | {{.ProcPath}}
|
||||||
# Report On {{.ThisHostID}} ########################################
|
# Report On {{.ThisHostID}} ########################################
|
||||||
User | {{.ProcUserName}}
|
User | {{.ProcUserName}}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
const Oplog = `
|
const Oplog = `
|
||||||
# Oplog ########################################################################################
|
# Oplog ##################################################################################################
|
||||||
Oplog Size {{.Size}} Mb
|
Oplog Size {{.Size}} Mb
|
||||||
Oplog Used {{.UsedMB}} Mb
|
Oplog Used {{.UsedMB}} Mb
|
||||||
Oplog Length {{.Running}}
|
Oplog Length {{.Running}}
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
const Replicas = `
|
const Replicas = `
|
||||||
# Instances ####################################################################################
|
# Instances ##############################################################################################
|
||||||
ID Host Type ReplSet
|
ID Host Type ReplSet Engine
|
||||||
{{- if . -}}
|
{{- if . -}}
|
||||||
{{- range . }}
|
{{- range . }}
|
||||||
{{printf "% 3d" .Id}} {{printf "%-30s" .Name}} {{printf "%-30s" .StateStr}} {{printf "%10s" .Set -}}
|
{{printf "% 3d" .Id}} {{printf "%-30s" .Name}} {{printf "%-30s" .StateStr}} {{printf "%10s" .Set }} {{printf "%20s" .StorageEngine.Name -}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{else}}
|
{{else}}
|
||||||
No replica sets found
|
no replica sets found
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
const RunningOps = `
|
const RunningOps = `
|
||||||
# Running Ops ##################################################################################
|
# Running Ops ############################################################################################
|
||||||
|
|
||||||
Type Min Max Avg
|
Type Min Max Avg
|
||||||
Insert {{printf "% 8d" .Insert.Min}} {{printf "% 8d" .Insert.Max}} {{printf "% 8d" .Insert.Avg}}/{{.SampleRate}}
|
Insert {{printf "% 8d" .Insert.Min}} {{printf "% 8d" .Insert.Max}} {{printf "% 8d" .Insert.Avg}}/{{.SampleRate}}
|
||||||
|
@@ -1,9 +1,16 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
const Security = `
|
const Security = `
|
||||||
# Security #####################################################################################
|
# Security ###############################################################################################
|
||||||
Users {{.Users}}
|
Users : {{.Users}}
|
||||||
Roles {{.Roles}}
|
Roles : {{.Roles}}
|
||||||
Auth {{.Auth}}
|
Auth : {{.Auth}}
|
||||||
SSL {{.SSL}}
|
SSL : {{.SSL}}
|
||||||
`
|
Port : {{.Port}}
|
||||||
|
Bind IP: {{.BindIP}}
|
||||||
|
{{- if .WarningMsgs -}}
|
||||||
|
{{- range .WarningMsgs }}
|
||||||
|
{{ . }}
|
||||||
|
{{end}}
|
||||||
|
{{end }}
|
||||||
|
`
|
||||||
|
Reference in New Issue
Block a user