mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-13 14:39:28 +00:00
PT-1891 Fixed mongodb-summary connection with ssl (#469)
* PT-1891 Fixed mongodb-summary connection with ssl - Added SSL connection options - Fixed old tests - Replaced gofmt by gofumpt in Makefile - There are no ssl test for mongodb-summary because the current sandbox doesnt support it * PT-1891 Ran gofumports * PMM-1891 Fixes for CR * PT-1891 Decreased minimum TLS reqs for compatibility
This commit is contained in:
@@ -138,8 +138,8 @@ test: ## Run tests
|
||||
@./runtests.sh
|
||||
|
||||
format: ## Format source code.
|
||||
gofmt -w -s $(FILES)
|
||||
goimports -local github.com/percona/pmm-managed -l -w $(FILES)
|
||||
gofumpt -w -s $(FILES)
|
||||
gofumports -local github.com/percona/pmm-managed -l -w $(FILES)
|
||||
|
||||
vet: ## Run vet on Go code
|
||||
@echo ">> vetting code"
|
||||
|
@@ -75,10 +75,8 @@ func DefaultConfigFiles(toolName string) ([]string, error) {
|
||||
}
|
||||
|
||||
func DefaultConfig(toolname string) *Config {
|
||||
|
||||
files, _ := DefaultConfigFiles(toolname)
|
||||
return NewConfig(files...)
|
||||
|
||||
}
|
||||
|
||||
func NewConfig(files ...string) *Config {
|
||||
@@ -94,7 +92,6 @@ func NewConfig(files ...string) *Config {
|
||||
}
|
||||
|
||||
func read(filename string, opts map[string]interface{}) error {
|
||||
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -135,7 +132,7 @@ func read(filename string, opts map[string]interface{}) error {
|
||||
}
|
||||
|
||||
if f == float64(int64(f)) {
|
||||
opts[key] = int64(f) //int64
|
||||
opts[key] = int64(f) // int64
|
||||
continue
|
||||
}
|
||||
|
||||
|
@@ -11,7 +11,6 @@ import (
|
||||
)
|
||||
|
||||
func TestReadConfig(t *testing.T) {
|
||||
|
||||
rootPath, err := tutil.RootPath()
|
||||
if err != nil {
|
||||
t.Errorf("cannot get root path: %s", err)
|
||||
@@ -69,7 +68,6 @@ func TestReadConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestOverrideConfig(t *testing.T) {
|
||||
|
||||
rootPath, err := tutil.RootPath()
|
||||
if err != nil {
|
||||
t.Errorf("cannot get root path: %s", err)
|
||||
@@ -131,7 +129,6 @@ func TestOverrideConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDefaultFiles(t *testing.T) {
|
||||
|
||||
user, _ := user.Current()
|
||||
toolname := "pt-testing"
|
||||
|
||||
@@ -150,5 +147,4 @@ func TestDefaultFiles(t *testing.T) {
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("got %#v\nwant: %#v\n", got, want)
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -5,8 +5,8 @@ import (
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/models"
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/models"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@@ -108,17 +108,15 @@ func LoadBson(filename string, destination interface{}) error {
|
||||
}
|
||||
|
||||
func WriteJson(filename string, data interface{}) error {
|
||||
|
||||
buf, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ioutil.WriteFile(filename, buf, 0777)
|
||||
err = ioutil.WriteFile(filename, buf, 0o777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func ShouldUpdateSamples() bool {
|
||||
|
@@ -12,7 +12,6 @@ import (
|
||||
)
|
||||
|
||||
func TestCheckUpdates(t *testing.T) {
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
body, _ := ioutil.ReadAll(r.Body)
|
||||
m := strings.Split(string(body), ";")
|
||||
@@ -39,11 +38,9 @@ func TestCheckUpdates(t *testing.T) {
|
||||
if msg == "" {
|
||||
t.Error("got empty response")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEmptyResponse(t *testing.T) {
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprint(w, "")
|
||||
}))
|
||||
@@ -57,5 +54,4 @@ func TestEmptyResponse(t *testing.T) {
|
||||
if msg != "" {
|
||||
t.Error("response should return error due to empty body")
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -11,10 +11,8 @@ import (
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
)
|
||||
|
||||
var (
|
||||
// DocsBufferSize is the buffer size to store documents from the MongoDB profiler
|
||||
DocsBufferSize = 100
|
||||
)
|
||||
// DocsBufferSize is the buffer size to store documents from the MongoDB profiler
|
||||
var DocsBufferSize = 100
|
||||
|
||||
// Profiler interface
|
||||
type Profiler interface {
|
||||
|
@@ -34,9 +34,11 @@ type OpLogs []OplogInfo
|
||||
func (s OpLogs) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s OpLogs) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
func (s OpLogs) Less(i, j int) bool {
|
||||
return s[i].TimeDiffHours < s[j].TimeDiffHours
|
||||
}
|
||||
|
@@ -4,8 +4,11 @@ import (
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
)
|
||||
|
||||
type ReplicaSetConfigTags map[string]string
|
||||
type GetLastErrorModes map[string]*ReplicaSetConfigTags
|
||||
type (
|
||||
ReplicaSetConfigTags map[string]string
|
||||
|
||||
GetLastErrorModes map[string]*ReplicaSetConfigTags
|
||||
)
|
||||
|
||||
// https://docs.mongodb.com/v3.2/reference/command/getLastError/#dbcmd.getLastError
|
||||
type GetLastErrorDefaults struct {
|
||||
|
@@ -239,7 +239,6 @@ func TestReplicasetConfig(t *testing.T) {
|
||||
Message: "not running with --replSet",
|
||||
Labels: []string(nil),
|
||||
Name: "NoReplicationEnabled",
|
||||
Wrapped: error(nil),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -251,7 +250,6 @@ func TestReplicasetConfig(t *testing.T) {
|
||||
Message: "no such cmd: replSetGetConfig",
|
||||
Labels: []string(nil),
|
||||
Name: "CommandNotFound",
|
||||
Wrapped: error(nil),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -272,9 +270,11 @@ func TestReplicasetConfig(t *testing.T) {
|
||||
|
||||
rs, err := ReplicasetConfig(ctx, client)
|
||||
assert.Equal(t, tc.wantError, err, fmt.Sprintf("%v", tc.port))
|
||||
|
||||
if tc.wantError != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
assert.Equal(t, tc.wantID, rs.Config.ID)
|
||||
assert.Equal(t, tc.wantConfigServer, rs.Config.ConfigServer)
|
||||
assert.NotEmpty(t, rs.Config.Settings.ReplicaSetID.Hex())
|
||||
|
@@ -70,7 +70,6 @@ type report struct {
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
opts, err := getOptions()
|
||||
if err != nil {
|
||||
log.Errorf("error processing command line arguments: %s", err)
|
||||
@@ -193,7 +192,6 @@ func main() {
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
|
||||
}
|
||||
|
||||
func formatResults(rep report, outputFormat string) ([]byte, error) {
|
||||
@@ -368,7 +366,6 @@ func getHeaders(opts *cliOptions) []string {
|
||||
}
|
||||
|
||||
func getQueryTemplate() string {
|
||||
|
||||
t := `
|
||||
# Query {{.Rank}}: {{printf "% 0.2f" .QPS}} QPS, ID {{.ID}}
|
||||
# Ratio {{Format .Ratio 7.2}} (docs scanned/returned)
|
||||
@@ -522,7 +519,6 @@ func sortQueries(queries []stats.QueryStats, orderby []string) []stats.QueryStat
|
||||
|
||||
OrderedBy(sortFuncs...).Sort(queries)
|
||||
return queries
|
||||
|
||||
}
|
||||
|
||||
func isProfilerEnabled(ctx context.Context, clientOptions *options.ClientOptions) (bool, error) {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
package main
|
||||
|
||||
//TODO: Rewrite tests to use the new sandbox
|
||||
// TODO: Rewrite tests to use the new sandbox
|
||||
|
||||
// const (
|
||||
// samples = "/src/go/tests/"
|
||||
|
@@ -3,11 +3,16 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -39,18 +44,23 @@ const (
|
||||
DefaultOutputFormat = "text"
|
||||
typeMongos = "mongos"
|
||||
|
||||
// Exit Codes
|
||||
// Exit Codes.
|
||||
cannotFormatResults = 1
|
||||
cannotParseCommandLineParameters = 2
|
||||
cannotGetHostInfo = 3
|
||||
cannotGetReplicasetMembers = 4
|
||||
cannotGetClientOptions = 4
|
||||
cannotConnectToMongoDB = 5
|
||||
)
|
||||
|
||||
//nolint:gochecknoglobals
|
||||
var (
|
||||
Build string = "2020-04-23" // nolint
|
||||
GoVersion string = "1.14.1" // nolint
|
||||
Build string = "2020-04-23"
|
||||
GoVersion string = "1.14.1"
|
||||
Version string = "3.2.0"
|
||||
Commit string
|
||||
|
||||
defaultConnectionTimeout = 3 * time.Second
|
||||
directConnection = true
|
||||
)
|
||||
|
||||
type TimedStats struct {
|
||||
@@ -69,6 +79,7 @@ type opCounters struct {
|
||||
Command TimedStats
|
||||
SampleRate time.Duration
|
||||
}
|
||||
|
||||
type hostInfo struct {
|
||||
Hostname string
|
||||
HostOsType string
|
||||
@@ -164,14 +175,11 @@ func main() {
|
||||
opts, err := parseFlags()
|
||||
if err != nil {
|
||||
log.Errorf("cannot get parameters: %s", err.Error())
|
||||
|
||||
os.Exit(cannotParseCommandLineParameters)
|
||||
}
|
||||
if opts == nil && err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if opts.Help {
|
||||
getopt.Usage()
|
||||
if opts == nil && err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -187,6 +195,7 @@ func main() {
|
||||
fmt.Printf("Version %s\n", Version)
|
||||
fmt.Printf("Build: %s using %s\n", Build, GoVersion)
|
||||
fmt.Printf("Commit: %s\n", Commit)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -201,34 +210,46 @@ func main() {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
clientOptions := getClientOptions(opts)
|
||||
clientOptions, err := getClientOptions(opts)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
|
||||
os.Exit(cannotGetClientOptions)
|
||||
}
|
||||
|
||||
client, err := mongo.NewClient(clientOptions)
|
||||
if err != nil {
|
||||
log.Fatalf("Cannot get a MongoDB client: %s", err)
|
||||
log.Errorf("Cannot get a MongoDB client: %s", err)
|
||||
|
||||
os.Exit(cannotConnectToMongoDB)
|
||||
}
|
||||
|
||||
if err := client.Connect(ctx); err != nil {
|
||||
log.Fatalf("Cannot connect to MongoDB: %s", err)
|
||||
log.Errorf("Cannot connect to MongoDB: %s", err)
|
||||
os.Exit(cannotConnectToMongoDB)
|
||||
}
|
||||
|
||||
defer client.Disconnect(ctx) // nolint
|
||||
|
||||
hostnames, err := util.GetHostnames(ctx, client)
|
||||
if err != nil && errors.Is(err, util.ShardingNotEnabledError) {
|
||||
log.Errorf("Cannot get hostnames: %s", err)
|
||||
}
|
||||
|
||||
log.Debugf("hostnames: %v", hostnames)
|
||||
|
||||
ci := &collectedInfo{}
|
||||
|
||||
ci.HostInfo, err = getHostInfo(ctx, client)
|
||||
if err != nil {
|
||||
message := fmt.Sprintf("Cannot get host info for %q: %s", opts.Host, err.Error())
|
||||
log.Errorf(message)
|
||||
os.Exit(cannotGetHostInfo)
|
||||
log.Errorf("Cannot get host info for %q: %s", opts.Host, err)
|
||||
os.Exit(cannotGetHostInfo) //nolint:gocritic
|
||||
}
|
||||
|
||||
if ci.ReplicaMembers, err = util.GetReplicasetMembers(ctx, clientOptions); err != nil {
|
||||
log.Warnf("[Error] cannot get replicaset members: %v\n", err)
|
||||
}
|
||||
|
||||
log.Debugf("replicaMembers:\n%+v\n", ci.ReplicaMembers)
|
||||
|
||||
if opts.RunningOpsSamples > 0 && opts.RunningOpsInterval > 0 {
|
||||
@@ -274,9 +295,10 @@ func main() {
|
||||
|
||||
out, err := formatResults(ci, opts.OutputFormat)
|
||||
if err != nil {
|
||||
log.Errorf("Cannot format the results: %s", err.Error())
|
||||
log.Errorf("Cannot format the results: %s", err)
|
||||
os.Exit(cannotFormatResults)
|
||||
}
|
||||
|
||||
fmt.Println(string(out))
|
||||
}
|
||||
|
||||
@@ -287,8 +309,9 @@ func formatResults(ci *collectedInfo, format string) ([]byte, error) {
|
||||
case "json":
|
||||
b, err := json.MarshalIndent(ci, "", " ")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("[Error] Cannot convert results to json: %s", err.Error())
|
||||
return nil, errors.Wrap(err, "Cannot convert results to json")
|
||||
}
|
||||
|
||||
buf = bytes.NewBuffer(b)
|
||||
default:
|
||||
buf = new(bytes.Buffer)
|
||||
@@ -338,6 +361,7 @@ func getHostInfo(ctx context.Context, client *mongo.Client) (*hostInfo, error) {
|
||||
hi := proto.HostInfo{}
|
||||
if err := client.Database("admin").RunCommand(ctx, primitive.M{"hostInfo": 1}).Decode(&hi); err != nil {
|
||||
log.Debugf("run('hostInfo') error: %s", err)
|
||||
|
||||
return nil, errors.Wrap(err, "GetHostInfo.hostInfo")
|
||||
}
|
||||
|
||||
@@ -393,12 +417,15 @@ func countMongodProcesses() (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
count := 0
|
||||
|
||||
for _, pid := range pids {
|
||||
p, err := process.NewProcess(pid)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if name, _ := p.Name(); name == "mongod" || name == typeMongos {
|
||||
count++
|
||||
}
|
||||
@@ -440,6 +467,7 @@ func getClusterwideInfo(ctx context.Context, client *mongo.Client) (*clusterwide
|
||||
if collStats.Sharded {
|
||||
cwi.ShardedDataSize += collStats.Size
|
||||
cwi.ShardedColsCount++
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -464,11 +492,14 @@ func sizeAndUnit(size int64) (float64, string) {
|
||||
unit := []string{"bytes", "KB", "MB", "GB", "TB"}
|
||||
idx := 0
|
||||
newSize := float64(size)
|
||||
|
||||
for newSize > 1024 {
|
||||
newSize /= 1024
|
||||
idx++
|
||||
}
|
||||
|
||||
newSize = float64(int64(newSize*100)) / 100
|
||||
|
||||
return newSize, unit[idx]
|
||||
}
|
||||
|
||||
@@ -486,7 +517,10 @@ func getSecuritySettings(ctx context.Context, client *mongo.Client, ver string)
|
||||
}
|
||||
|
||||
cmdOpts := proto.CommandLineOptions{}
|
||||
err = client.Database("admin").RunCommand(ctx, primitive.D{{"getCmdLineOpts", 1}, {"recordStats", 1}}).Decode(&cmdOpts)
|
||||
err = client.Database("admin").RunCommand(ctx, primitive.D{
|
||||
{Key: "getCmdLineOpts", Value: 1},
|
||||
{Key: "recordStats", Value: 1},
|
||||
}).Decode(&cmdOpts)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot get command line options")
|
||||
}
|
||||
@@ -503,7 +537,7 @@ func getSecuritySettings(ctx context.Context, client *mongo.Client, ver string)
|
||||
s.BindIP = cmdOpts.Parsed.Net.BindIP
|
||||
s.Port = cmdOpts.Parsed.Net.Port
|
||||
|
||||
if cmdOpts.Parsed.Net.BindIP == "" {
|
||||
if cmdOpts.Parsed.Net.BindIP == "" { //nolint:nestif
|
||||
if prior26 {
|
||||
s.WarningMsgs = append(s.WarningMsgs, "WARNING: You might be insecure. There is no IP binding")
|
||||
}
|
||||
@@ -586,7 +620,11 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
|
||||
// count + 1 because we need 1st reading to stablish a base to measure variation
|
||||
for i := 0; i < count+1; i++ {
|
||||
<-ticker.C
|
||||
err := client.Database("admin").RunCommand(ctx, primitive.D{{"serverStatus", 1}, {"recordStats", 1}}).Decode(&ss)
|
||||
|
||||
err := client.Database("admin").RunCommand(ctx, primitive.D{
|
||||
{Key: "serverStatus", Value: 1},
|
||||
{Key: "recordStats", Value: 1},
|
||||
}).Decode(&ss)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -598,6 +636,7 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
|
||||
prevOpCount.Insert.Total = ss.Opcounters.Insert
|
||||
prevOpCount.Query.Total = ss.Opcounters.Query
|
||||
prevOpCount.Update.Total = ss.Opcounters.Update
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -631,57 +670,63 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
|
||||
}
|
||||
|
||||
// Insert --------------------------------------
|
||||
if delta.Opcounters.Insert > oc.Insert.Max {
|
||||
switch {
|
||||
case delta.Opcounters.Insert > oc.Insert.Max:
|
||||
oc.Insert.Max = delta.Opcounters.Insert
|
||||
}
|
||||
if delta.Opcounters.Insert < oc.Insert.Min {
|
||||
case delta.Opcounters.Insert < oc.Insert.Min:
|
||||
oc.Insert.Min = delta.Opcounters.Insert
|
||||
}
|
||||
|
||||
oc.Insert.Total += delta.Opcounters.Insert
|
||||
|
||||
// Query ---------------------------------------
|
||||
if delta.Opcounters.Query > oc.Query.Max {
|
||||
switch {
|
||||
case delta.Opcounters.Query > oc.Query.Max:
|
||||
oc.Query.Max = delta.Opcounters.Query
|
||||
}
|
||||
if delta.Opcounters.Query < oc.Query.Min {
|
||||
case delta.Opcounters.Query < oc.Query.Min:
|
||||
oc.Query.Min = delta.Opcounters.Query
|
||||
}
|
||||
|
||||
oc.Query.Total += delta.Opcounters.Query
|
||||
|
||||
// Command -------------------------------------
|
||||
if delta.Opcounters.Command > oc.Command.Max {
|
||||
switch {
|
||||
case delta.Opcounters.Command > oc.Command.Max:
|
||||
oc.Command.Max = delta.Opcounters.Command
|
||||
}
|
||||
if delta.Opcounters.Command < oc.Command.Min {
|
||||
case delta.Opcounters.Command < oc.Command.Min:
|
||||
oc.Command.Min = delta.Opcounters.Command
|
||||
}
|
||||
|
||||
oc.Command.Total += delta.Opcounters.Command
|
||||
|
||||
// Update --------------------------------------
|
||||
if delta.Opcounters.Update > oc.Update.Max {
|
||||
switch {
|
||||
case delta.Opcounters.Update > oc.Update.Max:
|
||||
oc.Update.Max = delta.Opcounters.Update
|
||||
}
|
||||
if delta.Opcounters.Update < oc.Update.Min {
|
||||
case delta.Opcounters.Update < oc.Update.Min:
|
||||
oc.Update.Min = delta.Opcounters.Update
|
||||
}
|
||||
|
||||
oc.Update.Total += delta.Opcounters.Update
|
||||
|
||||
// Delete --------------------------------------
|
||||
if delta.Opcounters.Delete > oc.Delete.Max {
|
||||
switch {
|
||||
case delta.Opcounters.Delete > oc.Delete.Max:
|
||||
oc.Delete.Max = delta.Opcounters.Delete
|
||||
}
|
||||
if delta.Opcounters.Delete < oc.Delete.Min {
|
||||
case delta.Opcounters.Delete < oc.Delete.Min:
|
||||
oc.Delete.Min = delta.Opcounters.Delete
|
||||
}
|
||||
|
||||
oc.Delete.Total += delta.Opcounters.Delete
|
||||
|
||||
// GetMore -------------------------------------
|
||||
if delta.Opcounters.GetMore > oc.GetMore.Max {
|
||||
switch {
|
||||
case delta.Opcounters.GetMore > oc.GetMore.Max:
|
||||
oc.GetMore.Max = delta.Opcounters.GetMore
|
||||
}
|
||||
if delta.Opcounters.GetMore < oc.GetMore.Min {
|
||||
case delta.Opcounters.GetMore < oc.GetMore.Min:
|
||||
oc.GetMore.Min = delta.Opcounters.GetMore
|
||||
}
|
||||
|
||||
oc.GetMore.Total += delta.Opcounters.GetMore
|
||||
|
||||
prevOpCount.Insert.Total = ss.Opcounters.Insert
|
||||
@@ -690,8 +735,8 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
|
||||
prevOpCount.Update.Total = ss.Opcounters.Update
|
||||
prevOpCount.Delete.Total = ss.Opcounters.Delete
|
||||
prevOpCount.GetMore.Total = ss.Opcounters.GetMore
|
||||
|
||||
}
|
||||
|
||||
ticker.Stop()
|
||||
|
||||
oc.Insert.Avg = oc.Insert.Total
|
||||
@@ -707,11 +752,12 @@ func getOpCountersStats(ctx context.Context, client *mongo.Client, count int,
|
||||
}
|
||||
|
||||
func getProcInfo(pid int32, templateData *procInfo) error {
|
||||
//proc, err := process.NewProcess(templateData.ServerStatus.Pid)
|
||||
// proc, err := process.NewProcess(templateData.ServerStatus.Pid)
|
||||
proc, err := process.NewProcess(pid)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot get process %d", pid)
|
||||
return errors.New(fmt.Sprintf("cannot get process %d", pid))
|
||||
}
|
||||
|
||||
ct, err := proc.CreateTime()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -742,6 +788,7 @@ func GetBalancerStats(ctx context.Context, client *mongo.Client) (*proto.Balance
|
||||
event := item.Id.Event
|
||||
note := item.Id.Note
|
||||
count := item.Count
|
||||
|
||||
switch event {
|
||||
case "moveChunk.to", "moveChunk.from", "moveChunk.commit":
|
||||
if note == "success" || note == "" {
|
||||
@@ -760,7 +807,7 @@ func GetBalancerStats(ctx context.Context, client *mongo.Client) (*proto.Balance
|
||||
}
|
||||
|
||||
func GetShardingChangelogStatus(ctx context.Context, client *mongo.Client) (*proto.ShardingChangelogStats, error) {
|
||||
var qresults []proto.ShardingChangelogSummary
|
||||
qresults := []proto.ShardingChangelogSummary{}
|
||||
coll := client.Database("config").Collection("changelog")
|
||||
match := primitive.M{"time": primitive.M{"$gt": time.Now().Add(-240 * time.Hour)}}
|
||||
group := primitive.M{"_id": primitive.M{"event": "$what", "note": "$details.note"}, "count": primitive.M{"$sum": 1}}
|
||||
@@ -776,6 +823,7 @@ func GetShardingChangelogStatus(ctx context.Context, client *mongo.Client) (*pro
|
||||
if err := cursor.Decode(&res); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot decode GetShardingChangelogStatus")
|
||||
}
|
||||
|
||||
qresults = append(qresults, res)
|
||||
}
|
||||
|
||||
@@ -796,6 +844,7 @@ func isPrivateNetwork(ip string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
addr := net.ParseIP(ip)
|
||||
if cidrnet.Contains(addr) {
|
||||
return true, nil
|
||||
@@ -803,7 +852,6 @@ func isPrivateNetwork(ip string) (bool, error) {
|
||||
}
|
||||
|
||||
return false, nil
|
||||
|
||||
}
|
||||
|
||||
func externalIP() (string, error) {
|
||||
@@ -811,17 +859,21 @@ func externalIP() (string, error) {
|
||||
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) {
|
||||
@@ -830,9 +882,11 @@ func externalIP() (string, error) {
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue // not an ipv4 address
|
||||
@@ -840,6 +894,7 @@ func externalIP() (string, error) {
|
||||
return ip.String(), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("are you connected to the network?")
|
||||
}
|
||||
|
||||
@@ -880,8 +935,8 @@ func parseFlags() (*cliOptions, error) {
|
||||
gop.StringVarLong(&opts.SSLPEMKeyFile, "sslPEMKeyFile", 0, "SSL client PEM file used for authentication")
|
||||
|
||||
gop.SetParameters("host[:port]")
|
||||
|
||||
gop.Parse(os.Args)
|
||||
|
||||
if gop.NArgs() > 0 {
|
||||
opts.Host = gop.Arg(0)
|
||||
gop.Parse(gop.Args())
|
||||
@@ -889,19 +944,25 @@ func parseFlags() (*cliOptions, error) {
|
||||
|
||||
if gop.IsSet("password") && opts.Password == "" {
|
||||
print("Password: ")
|
||||
|
||||
pass, err := gopass.GetPasswd()
|
||||
if err != nil {
|
||||
return opts, err
|
||||
}
|
||||
|
||||
opts.Password = string(pass)
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(opts.Host, "mongodb://") {
|
||||
opts.Host = "mongodb://" + opts.Host
|
||||
}
|
||||
|
||||
if opts.Help {
|
||||
gop.PrintUsage(os.Stdout)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if opts.OutputFormat != "json" && opts.OutputFormat != "text" {
|
||||
log.Infof("Invalid output format '%s'. Using text format", opts.OutputFormat)
|
||||
}
|
||||
@@ -920,27 +981,93 @@ func getChunksCount(ctx context.Context, client *mongo.Client) ([]proto.ChunksBy
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
res := proto.ChunksByCollection{}
|
||||
if err := cursor.Decode(&res); err != nil {
|
||||
return nil, errors.Wrap(err, "cannot decode chunks aggregation")
|
||||
}
|
||||
|
||||
result = append(result, res)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func getClientOptions(opts *cliOptions) *options.ClientOptions {
|
||||
func getClientOptions(opts *cliOptions) (*options.ClientOptions, error) {
|
||||
clientOptions := options.Client().ApplyURI(opts.Host)
|
||||
|
||||
clientOptions.ServerSelectionTimeout = &defaultConnectionTimeout
|
||||
clientOptions.Direct = &directConnection
|
||||
credential := options.Credential{}
|
||||
if opts.User != "" {
|
||||
credential.Username = opts.User
|
||||
clientOptions.SetAuth(credential)
|
||||
}
|
||||
|
||||
if opts.Password != "" {
|
||||
credential.Password = opts.Password
|
||||
credential.PasswordSet = true
|
||||
clientOptions.SetAuth(credential)
|
||||
}
|
||||
return clientOptions
|
||||
|
||||
if opts.SSLPEMKeyFile != "" || opts.SSLCAFile != "" {
|
||||
tlsConfig, err := getTLSConfig(opts.SSLPEMKeyFile, opts.SSLCAFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "cannot read SSL certificate files")
|
||||
}
|
||||
|
||||
clientOptions.TLSConfig = tlsConfig
|
||||
}
|
||||
|
||||
return clientOptions, nil
|
||||
}
|
||||
|
||||
func getTLSConfig(sslPEMKeyFile, sslCAFile string) (*tls.Config, error) {
|
||||
tlsConfig := &tls.Config{
|
||||
MinVersion: tls.VersionTLS10,
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
|
||||
roots := x509.NewCertPool()
|
||||
|
||||
if sslPEMKeyFile != "" {
|
||||
crt, err := ioutil.ReadFile(filepath.Clean(expandHome(sslPEMKeyFile)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cert, err := tls.X509KeyPair(crt, crt)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
|
||||
if sslCAFile != "" {
|
||||
ca, err := ioutil.ReadFile(filepath.Clean(expandHome(sslCAFile)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roots.AppendCertsFromPEM(ca)
|
||||
tlsConfig.RootCAs = roots
|
||||
}
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
func expandHome(path string) string {
|
||||
usr, _ := user.Current()
|
||||
dir := usr.HomeDir
|
||||
|
||||
switch {
|
||||
case path == "~":
|
||||
path = dir
|
||||
case strings.HasPrefix(path, "~/"):
|
||||
path = filepath.Join(dir, path[2:])
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
@@ -99,8 +99,8 @@ func TestClusterWideInfo(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func addToCounters(ss proto.ServerStatus, increment int64) proto.ServerStatus {
|
||||
ss.Opcounters.Command += increment
|
||||
ss.Opcounters.Delete += increment
|
||||
|
@@ -85,7 +85,6 @@ func GetOplogInfo(ctx context.Context, hostnames []string, co *options.ClientOpt
|
||||
|
||||
sort.Sort(results)
|
||||
return results, nil
|
||||
|
||||
}
|
||||
|
||||
func getOplogCollection(ctx context.Context, client *mongo.Client) (string, error) {
|
||||
|
@@ -31,6 +31,7 @@ type connOpts struct {
|
||||
Password string
|
||||
DisableSSL bool
|
||||
}
|
||||
|
||||
type cliOptions struct {
|
||||
app *kingpin.Application
|
||||
connOpts connOpts
|
||||
@@ -110,7 +111,6 @@ func main() {
|
||||
if err := masterTmpl.ExecuteTemplate(os.Stdout, "report", info); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func connect(dsn string) (*sql.DB, error) {
|
||||
@@ -131,29 +131,29 @@ func funcsMap() template.FuncMap {
|
||||
if len(s) < size {
|
||||
return s
|
||||
}
|
||||
return s[:size]+"..."
|
||||
return s[:size] + "..."
|
||||
},
|
||||
"convertnullstring": func(s sql.NullString) string {
|
||||
if s.Valid {
|
||||
return s.String
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
"convertnullint64": func(s sql.NullInt64) int64 {
|
||||
if s.Valid {
|
||||
return s.Int64
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
},
|
||||
"convertnullfloat64": func(s sql.NullFloat64) float64 {
|
||||
if s.Valid {
|
||||
return s.Float64
|
||||
} else {
|
||||
return 0.0
|
||||
}
|
||||
},
|
||||
"convertnullstring": func(s sql.NullString) string {
|
||||
if s.Valid {
|
||||
return s.String
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
"convertnullint64": func(s sql.NullInt64) int64 {
|
||||
if s.Valid {
|
||||
return s.Int64
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
},
|
||||
"convertnullfloat64": func(s sql.NullFloat64) float64 {
|
||||
if s.Valid {
|
||||
return s.Float64
|
||||
} else {
|
||||
return 0.0
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,8 +5,8 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/internal/tu"
|
||||
"github.com/percona/percona-toolkit/src/go/lib/pginfo"
|
||||
"github.com/percona/percona-toolkit/src/go/pt-pg-summary/internal/tu"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -37,7 +37,7 @@ func TestConnection(t *testing.T) {
|
||||
// use an "external" IP to simulate a remote host
|
||||
tests := append(tests, Test{"remote_host", tu.PG9DockerIP, tu.DefaultPGPort, tu.Username, tu.Password})
|
||||
// use IPV6 for PostgreSQL 9
|
||||
//tests := append(tests, Test{"IPV6", tu.IPv6Host, tu.IPv6PG9Port, tu.Username, tu.Password})
|
||||
// tests := append(tests, Test{"IPV6", tu.IPv6Host, tu.IPv6PG9Port, tu.Username, tu.Password})
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
@@ -48,16 +48,15 @@ func TestConnection(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNewWithLogger(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
|
||||
test.host, test.port, test.username, test.password, "postgres")
|
||||
db, err := connect(dsn);
|
||||
db, err := connect(dsn)
|
||||
if err != nil {
|
||||
t.Errorf("Cannot connect to the db using %q: %s", dsn, err)
|
||||
}
|
||||
@@ -65,21 +64,20 @@ func TestNewWithLogger(t *testing.T) {
|
||||
t.Errorf("Cannot run NewWithLogger using %q: %s", dsn, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func TestCollectGlobalInfo(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
|
||||
test.host, test.port, test.username, test.password, "postgres")
|
||||
db, err := connect(dsn);
|
||||
db, err := connect(dsn)
|
||||
if err != nil {
|
||||
t.Errorf("Cannot connect to the db using %q: %s", dsn, err)
|
||||
}
|
||||
info, err := pginfo.NewWithLogger(db, nil, 30, logger);
|
||||
info, err := pginfo.NewWithLogger(db, nil, 30, logger)
|
||||
if err != nil {
|
||||
t.Errorf("Cannot run NewWithLogger using %q: %s", dsn, err)
|
||||
}
|
||||
@@ -92,27 +90,27 @@ func TestCollectGlobalInfo(t *testing.T) {
|
||||
t.Errorf("Cannot collect global information using %q", dsn)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollectPerDatabaseInfo(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
|
||||
test.host, test.port, test.username, test.password, "postgres")
|
||||
db, err := connect(dsn);
|
||||
db, err := connect(dsn)
|
||||
if err != nil {
|
||||
t.Errorf("Cannot connect to the db using %q: %s", dsn, err)
|
||||
}
|
||||
info, err := pginfo.NewWithLogger(db, nil, 30, logger);
|
||||
info, err := pginfo.NewWithLogger(db, nil, 30, logger)
|
||||
if err != nil {
|
||||
t.Errorf("Cannot run New using %q: %s", dsn, err)
|
||||
}
|
||||
for _, dbName := range info.DatabaseNames() {
|
||||
dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s sslmode=disable dbname=%s",
|
||||
test.host, test.port, test.username, test.password, dbName)
|
||||
conn, err := connect(dsn);
|
||||
conn, err := connect(dsn)
|
||||
if err != nil {
|
||||
t.Errorf("Cannot connect to the %s database using %q: %s", dbName, dsn, err)
|
||||
}
|
||||
@@ -122,5 +120,5 @@ func TestCollectPerDatabaseInfo(t *testing.T) {
|
||||
conn.Close()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -13,7 +13,7 @@ func GetAllDatabases(db XODB) ([]*AllDatabases, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT datname ` +
|
||||
sqlstr := `SELECT datname ` +
|
||||
`FROM pg_database ` +
|
||||
`WHERE datistemplate = false`
|
||||
|
||||
|
@@ -24,7 +24,7 @@ func GetClusterInfos(db XODB) ([]*ClusterInfo, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT usename, now() AS "Time", ` +
|
||||
sqlstr := `SELECT usename, now() AS "Time", ` +
|
||||
`client_addr, ` +
|
||||
`client_hostname, ` +
|
||||
`version() AS version, ` +
|
||||
|
@@ -20,7 +20,7 @@ func GetConnectedClients(db XODB) ([]*ConnectedClients, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT usename, ` +
|
||||
sqlstr := `SELECT usename, ` +
|
||||
`CASE WHEN client_hostname IS NULL THEN client_addr::text ELSE client_hostname END AS client, ` +
|
||||
`state, count(*) ` +
|
||||
`FROM pg_stat_activity ` +
|
||||
|
@@ -14,7 +14,7 @@ func GetConnections(db XODB) ([]*Connections, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT state, count(*) ` +
|
||||
sqlstr := `SELECT state, count(*) ` +
|
||||
`FROM pg_stat_activity ` +
|
||||
`GROUP BY 1`
|
||||
|
||||
|
@@ -27,7 +27,7 @@ func GetCounters(db XODB) ([]*Counters, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT COALESCE(datname, '') datname, numbackends, xact_commit, xact_rollback, ` +
|
||||
sqlstr := `SELECT COALESCE(datname, '') datname, numbackends, xact_commit, xact_rollback, ` +
|
||||
`blks_read, blks_hit, tup_returned, tup_fetched, tup_inserted, ` +
|
||||
`tup_updated, tup_deleted, conflicts, temp_files, ` +
|
||||
`temp_bytes, deadlocks ` +
|
||||
|
@@ -14,7 +14,7 @@ func GetDatabases(db XODB) ([]*Databases, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT datname, pg_size_pretty(pg_database_size(datname)) ` +
|
||||
sqlstr := `SELECT datname, pg_size_pretty(pg_database_size(datname)) ` +
|
||||
`FROM pg_stat_database ` +
|
||||
`WHERE datid <> 0`
|
||||
|
||||
|
@@ -22,7 +22,7 @@ func GetDatabaseWaitEvents(db XODB) ([]*DatabaseWaitEvents, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT c.relname, c.relkind, d.wait_event_type, d.wait_event, b.datname, count(*) ` +
|
||||
sqlstr := `SELECT c.relname, c.relkind, d.wait_event_type, d.wait_event, b.datname, count(*) ` +
|
||||
`FROM pg_locks a ` +
|
||||
`JOIN pg_stat_database b ON a.database=b.datid ` +
|
||||
`JOIN pg_class c ON a.relation=c.oid ` +
|
||||
|
@@ -14,7 +14,7 @@ func GetPortAndDatadir(db XODB) (*PortAndDatadir, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT name, ` +
|
||||
sqlstr := `SELECT name, ` +
|
||||
`setting ` +
|
||||
`FROM pg_settings ` +
|
||||
`WHERE name IN ('port','data_directory')`
|
||||
|
@@ -20,7 +20,7 @@ func GetSlaveHosts10s(db XODB) ([]*SlaveHosts10, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_lsn - replay_lsn) * 255 * 16 ^ 6 ) AS byte_lag ` +
|
||||
sqlstr := `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_lsn - replay_lsn) * 255 * 16 ^ 6 ) AS byte_lag ` +
|
||||
`FROM ( SELECT application_name, client_addr, client_hostname, state, ` +
|
||||
`('x' || lpad(split_part(sent_lsn::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS sent_lsn, ` +
|
||||
`('x' || lpad(split_part(replay_lsn::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS replay_lsn, ` +
|
||||
|
@@ -20,7 +20,7 @@ func GetSlaveHosts96s(db XODB) ([]*SlaveHosts96, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag ` +
|
||||
sqlstr := `SELECT application_name, client_addr, state, sent_offset - (replay_offset - (sent_xlog - replay_xlog) * 255 * 16 ^ 6 ) AS byte_lag ` +
|
||||
`FROM ( SELECT application_name, client_addr, client_hostname, state, ` +
|
||||
`('x' || lpad(split_part(sent_location::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS sent_xlog, ` +
|
||||
`('x' || lpad(split_part(replay_location::TEXT, '/', 1), 8, '0'))::bit(32)::bigint AS replay_xlog, ` +
|
||||
|
@@ -20,7 +20,7 @@ func GetTableAccesses(db XODB) ([]*TableAccess, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT c.relname, c.relkind, b.datname datname, count(*) FROM pg_locks a ` +
|
||||
sqlstr := `SELECT c.relname, c.relkind, b.datname datname, count(*) FROM pg_locks a ` +
|
||||
`JOIN pg_stat_database b ` +
|
||||
`ON a.database=b.datid ` +
|
||||
`JOIN pg_class c ` +
|
||||
|
@@ -18,7 +18,7 @@ func GetTableCacheHitRatio(db XODB) (*TableCacheHitRatio, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT 'cache hit rate' AS name, ` +
|
||||
sqlstr := `SELECT 'cache hit rate' AS name, ` +
|
||||
`CASE WHEN (sum(heap_blks_read) + sum(idx_blks_hit)) > 0 ` +
|
||||
`THEN ` +
|
||||
`sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) ` +
|
||||
|
@@ -15,7 +15,7 @@ func GetTablespaces(db XODB) ([]*Tablespaces, error) {
|
||||
var err error
|
||||
|
||||
// sql query
|
||||
var sqlstr = `SELECT spcname AS Name, ` +
|
||||
sqlstr := `SELECT spcname AS Name, ` +
|
||||
`pg_catalog.pg_get_userbyid(spcowner) AS Owner, ` +
|
||||
`pg_catalog.pg_tablespace_location(oid) AS Location ` +
|
||||
`FROM pg_catalog.pg_tablespace ` +
|
||||
|
@@ -57,7 +57,7 @@ var TPL = `{{define "report"}}
|
||||
+----------------------+----------------------+----------------------------------------------------+
|
||||
{{ end -}} {{/* end define */}}
|
||||
` +
|
||||
`{{- define "slaves_and_log_none" -}}
|
||||
`{{- define "slaves_and_log_none" -}}
|
||||
##### --- Slave and the lag with Master --- ####
|
||||
There are no slave hosts
|
||||
{{ end -}} {{/* end define */}}
|
||||
|
@@ -50,7 +50,7 @@ func encrypt(infile, outfile string, pass [32]byte) error {
|
||||
var iv [aes.BlockSize]byte
|
||||
stream := cipher.NewOFB(block, iv[:])
|
||||
|
||||
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Cannot create output file %q", outfile)
|
||||
}
|
||||
@@ -81,7 +81,7 @@ func decrypt(infile, outfile string, pass [32]byte) error {
|
||||
var iv [aes.BlockSize]byte
|
||||
stream := cipher.NewOFB(block, iv[:])
|
||||
|
||||
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
||||
outFile, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Cannot open %q for writing", outfile)
|
||||
}
|
||||
|
@@ -32,11 +32,9 @@ func TestProcessCliParams(t *testing.T) {
|
||||
t.Errorf("Test #%d expected error, have nil", i)
|
||||
}
|
||||
if !reflect.DeepEqual(opts, test.WantOpts) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCollect(t *testing.T) {
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user