Skip to content
This repository has been archived by the owner on Jun 21, 2022. It is now read-only.

PMM-4879 Adding support for defaults-file in new mysql service. #1068

Merged
merged 20 commits into from
Jun 11, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go 1.18

// Use for local development, but do not commit:
// replace github.com/percona/pmm => ../pmm
replace github.com/percona/pmm => github.com/pkadej/pmm v0.0.0-20220427173424-9aa771bbf8c1

// replace github.com/percona-platform/saas => ../saas
// replace github.com/percona-platform/dbaas-api => ../dbaas-api

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -465,13 +465,13 @@ github.com/percona-platform/dbaas-api v0.0.0-20220110092915-5aacd784d472 h1:Henk
github.com/percona-platform/dbaas-api v0.0.0-20220110092915-5aacd784d472/go.mod h1:WZZ3Hi+lAWCaGWmsrfkkvRQPkIa8n1OZ0s8Su+vbgus=
github.com/percona-platform/saas v0.0.0-20220427162947-f9d246ad0f16 h1:0fx16uGtl4MwrBwm9/VSoNEhjL0cXYxS0quEhLthGcc=
github.com/percona-platform/saas v0.0.0-20220427162947-f9d246ad0f16/go.mod h1:gFUwaFp6Ugu5qsBwiOVJYbDlzgZ77tmXdXGO7tG5xVI=
github.com/percona/pmm v0.0.0-20220427122756-c52cc545e1f3 h1:6IKHKNDNJADEN/YsvXcUiJ8M75/PW+bJZ3kMb+CL7kM=
github.com/percona/pmm v0.0.0-20220427122756-c52cc545e1f3/go.mod h1:FFbpyZXm+Ilg8M/GewuhdjJhPaW1/v1zjRRerYhCfEA=
github.com/percona/promconfig v0.2.4-0.20211110115058-98687f586f54 h1:aI1emmycDTGWKsBdxFPKZqohfBbK4y2ta9G4+RX7gVg=
github.com/percona/promconfig v0.2.4-0.20211110115058-98687f586f54/go.mod h1:Y2uXi5QNk71+ceJHuI9poank+0S1kjxd3K105fXKVkg=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkadej/pmm v0.0.0-20220427173424-9aa771bbf8c1 h1:O8OIMYgFTptOkFihK2xCUEoXBX5N0As7p47k+X6qk9s=
github.com/pkadej/pmm v0.0.0-20220427173424-9aa771bbf8c1/go.mod h1:FFbpyZXm+Ilg8M/GewuhdjJhPaW1/v1zjRRerYhCfEA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand Down
5 changes: 4 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ type gRPCServerDeps struct {
actions *agents.ActionsService
agentsStateUpdater *agents.StateUpdater
connectionCheck *agents.ConnectionChecker
defaultsFileParser *agents.DefaultsFileParser
grafanaClient *grafana.Client
checksService *checks.Service
dbaasClient *dbaas.Client
Expand Down Expand Up @@ -188,7 +189,7 @@ func runGRPCServer(ctx context.Context, deps *gRPCServerDeps) {

nodeSvc := management.NewNodeService(deps.db)
serviceSvc := management.NewServiceService(deps.db, deps.agentsStateUpdater, deps.vmdb)
mysqlSvc := management.NewMySQLService(deps.db, deps.agentsStateUpdater, deps.connectionCheck, deps.versionCache)
mysqlSvc := management.NewMySQLService(deps.db, deps.agentsStateUpdater, deps.connectionCheck, deps.versionCache, deps.defaultsFileParser)
mongodbSvc := management.NewMongoDBService(deps.db, deps.agentsStateUpdater, deps.connectionCheck)
postgresqlSvc := management.NewPostgreSQLService(deps.db, deps.agentsStateUpdater, deps.connectionCheck)
proxysqlSvc := management.NewProxySQLService(deps.db, deps.agentsStateUpdater, deps.connectionCheck)
Expand Down Expand Up @@ -729,6 +730,7 @@ func main() {
schedulerService := scheduler.New(db, backupService)
versionCache := versioncache.New(db, versioner)
emailer := alertmanager.NewEmailer(logrus.WithField("component", "alertmanager-emailer").Logger)
defaultsFileParser := agents.NewDefaultsFileParser(agentsRegistry)

serverParams := &server.Params{
DB: db,
Expand Down Expand Up @@ -929,6 +931,7 @@ func main() {
versionCache: versionCache,
supervisord: supervisord,
config: &cfg.Config,
defaultsFileParser: defaultsFileParser,
})
}()

Expand Down
26 changes: 26 additions & 0 deletions models/defaults_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// pmm-managed
// Copyright (C) 2017 Percona LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package models

// ParseDefaultsFileResult contains result of parsing defaults file.
type ParseDefaultsFileResult struct {
Username string
Password string
Host string
Port uint32
Socket string
}
2 changes: 2 additions & 0 deletions services/agents/channel/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ func (c *Channel) runReceiver() {
c.publish(msg.Id, msg.Status, p.GetVersions)
case *agentpb.AgentMessage_PbmSwitchPitr:
c.publish(msg.Id, msg.Status, p.PbmSwitchPitr)
case *agentpb.AgentMessage_ParseDefaultsFile:
c.publish(msg.Id, msg.Status, p.ParseDefaultsFile)

case nil:
c.cancel(msg.Id, errors.Errorf("unimplemented: failed to handle received message %s", msg))
Expand Down
47 changes: 47 additions & 0 deletions services/agents/channel/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,50 @@ func TestUnexpectedResponsePayloadFromAgent(t *testing.T) {
close(stopServer)
<-stop
}

func TestChannelForDefaultsFileParser(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what are we testing here

const count = 50
require.True(t, count > agentRequestsCap)

connect := func(ch *Channel) error {
testValue := "test"
testPort := uint32(123123)
for i := uint32(1); i <= count; i++ {
resp, err := ch.SendAndWaitResponse(&agentpb.ParseDefaultsFileRequest{})
assert.NotNil(t, resp)
parserResponse := resp.(*agentpb.ParseDefaultsFileResponse)
assert.Equal(t, parserResponse.Username, testValue)
assert.Equal(t, parserResponse.Password, testValue)
assert.Equal(t, parserResponse.Socket, testValue)
assert.Equal(t, parserResponse.Port, testPort)
assert.NoError(t, err)
}

assert.Nil(t, <-ch.Requests())
return nil
}

stream, _, teardown := setup(t, connect, io.EOF) // EOF = server exits from handler
defer teardown(t)

for i := uint32(1); i <= count; i++ {
msg, err := stream.Recv()
assert.NoError(t, err)
assert.Equal(t, i, msg.Id)
assert.NotNil(t, msg.GetParseDefaultsFile())

err = stream.Send(&agentpb.AgentMessage{
Id: i,
Payload: (&agentpb.ParseDefaultsFileResponse{
Username: "test",
Password: "test",
Port: 123123,
Socket: "test",
}).AgentMessageResponsePayload(),
})
assert.NoError(t, err)
}

err := stream.CloseSend()
assert.NoError(t, err)
}
98 changes: 98 additions & 0 deletions services/agents/parse_defaults_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// pmm-managed
// Copyright (C) 2017 Percona LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package agents

import (
"context"
"time"

"github.com/percona/pmm/api/agentpb"
"github.com/percona/pmm/api/inventorypb"
"github.com/pkg/errors"

"github.com/percona/pmm-managed/models"
"github.com/percona/pmm-managed/utils/logger"
)

// DefaultsFileParser requests from agent to parse defaultsFile.
type DefaultsFileParser struct {
r *Registry
}

// NewDefaultsFileParser creates new ParseDefaultsFile request.
func NewDefaultsFileParser(r *Registry) *DefaultsFileParser {
return &DefaultsFileParser{
r: r,
}
}

// ParseDefaultsFile sends request (with file path) to pmm-agent to parse defaults file.
func (p *DefaultsFileParser) ParseDefaultsFile(ctx context.Context, pmmAgentID, filePath string, serviceType models.ServiceType) (*models.ParseDefaultsFileResult, error) {
l := logger.Get(ctx)

pmmAgent, err := p.r.get(pmmAgentID)
if err != nil {
return nil, err
}

start := time.Now()
defer func() {
if dur := time.Since(start); dur > 5*time.Second {
l.Warnf("ParseDefaultsFile took %s.", dur)
}
}()
Comment on lines +52 to +57
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it realistic? Reading a file with few lines should not be a problem. And, I think, it should be handed in agent

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be written like this:

	defer func(start time.Time) {
		if dur := time.Since(start); dur > 5*time.Second {
			l.Warnf("ParseDefaultsFile took %s.", dur)
		}
	}(time.Now())

But yes, I also don't see benefit of this log


request, err := createRequest(filePath, serviceType)
if err != nil {
l.Debugf("can't create ParseDefaultsFileRequest %s", err)
return nil, err
}

resp, err := pmmAgent.channel.SendAndWaitResponse(request)
if err != nil {
return nil, err
}

l.Infof("ParseDefaultsFile response from agent: %+v.", resp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Debug level fits better here.

parserResponse, ok := resp.(*agentpb.ParseDefaultsFileResponse)
if !ok {
return nil, errors.New("wrong response from agent (not ParseDefaultsFileResponse model)")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add info regarding actual type?

}
if parserResponse.Error != "" {
return nil, errors.New(parserResponse.Error)
}

return &models.ParseDefaultsFileResult{
Username: parserResponse.Username,
Password: parserResponse.Password,
Host: parserResponse.Host,
Port: parserResponse.Port,
Socket: parserResponse.Socket,
}, nil
}

func createRequest(configPath string, serviceType models.ServiceType) (*agentpb.ParseDefaultsFileRequest, error) {
if serviceType == models.MySQLServiceType {
request := &agentpb.ParseDefaultsFileRequest{
ServiceType: inventorypb.ServiceType_MYSQL_SERVICE,
ConfigPath: configPath,
}
return request, nil
} else {
return nil, errors.Errorf("unhandled service type %s", serviceType)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return nil, errors.Errorf("unhandled service type %s", serviceType)
return nil, errors.Errorf("unsupported service type %s", serviceType)

}
}
41 changes: 41 additions & 0 deletions services/agents/parse_defaults_file_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// pmm-managed
// Copyright (C) 2017 Percona LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

package agents

import (
"testing"

"github.com/stretchr/testify/require"

"github.com/percona/pmm-managed/models"
)

func TestCreateRequest(t *testing.T) {
t.Parallel()
response, err := createRequest("/path/to/file", models.MySQLServiceType)

require.NoError(t, err)
require.NotNil(t, response, "ParseDefaultsFileRequest is nil")
}

func TestCreateRequestNotSupported(t *testing.T) {
t.Parallel()
response, err := createRequest("/path/to/file", models.PostgreSQLServiceType)

require.Error(t, err)
require.Nil(t, response, "ParseDefaultsFileRequest is not nil")
}
8 changes: 8 additions & 0 deletions services/management/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import (
//go:generate mockery -name=grafanaClient -case=snake -inpkg -testonly
//go:generate mockery -name=jobsService -case=snake -inpkg -testonly
//go:generate mockery -name=connectionChecker -case=snake -inpkg -testonly
//go:generate mockery -name=defaultsFileParser -case=snake -inpkg -testonly
//go:generate mockery -name=versionCache -case=snake -inpkg -testonly

// agentsRegistry is a subset of methods of agents.Registry used by this package.
// We use it instead of real type for testing and to avoid dependency cycle.
Expand Down Expand Up @@ -93,3 +95,9 @@ type connectionChecker interface {
type versionCache interface {
RequestSoftwareVersionsUpdate()
}

// defaultsFileParser is a subset of methods of agents.ParseDefaultsFile.
// We use it instead of real type for testing and to avoid dependency cycle.
type defaultsFileParser interface {
ParseDefaultsFile(ctx context.Context, pmmAgentID, filePath string, serviceType models.ServiceType) (*models.ParseDefaultsFileResult, error)
}
39 changes: 39 additions & 0 deletions services/management/mock_defaults_file_parser_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions services/management/mock_version_cache_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading