Skip to content

Commit

Permalink
PMM-10642: Initial structure for pmm cli (#1194)
Browse files Browse the repository at this point in the history
* PMM-10642: Initial structure for pmm cli
  • Loading branch information
Michal Kralik authored Sep 21, 2022
1 parent 4ea4dd2 commit a4e879e
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 33 deletions.
12 changes: 7 additions & 5 deletions admin/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ LD_FLAGS = -ldflags " \
"

release: ## Build pmm-admin release binary.
env CGO_ENABLED=0 go build -v $(LD_FLAGS) -o $(PMM_RELEASE_PATH)/pmm-admin
env CGO_ENABLED=0 go build -v $(LD_FLAGS) -o $(PMM_RELEASE_PATH)/pmm-admin ./cmd/pmm-admin/

install: ## Install pmm-admin binary.
go build -v $(LD_FLAGS) -o $(GOBIN)/pmm-admin
install: ## Install pmm & pmm-admin binary.
go build -v $(LD_FLAGS) -o $(GOBIN)/pmm-admin ./cmd/pmm-admin/
go build -v $(LD_FLAGS) -o $(GOBIN)/pmm ./cmd/pmm/

install-race: ## Install pmm-admin binary with race detector.
go build -v $(LD_FLAGS) -race -o $(GOBIN)/pmm-admin
install-race: ## Install pmm & pmm-admin binary with race detector.
go build -v $(LD_FLAGS) -race -o $(GOBIN)/pmm-admin ./cmd/pmm-admin/
go build -v $(LD_FLAGS) -race -o $(GOBIN)/pmm ./cmd/pmm/

TEST_FLAGS ?= -timeout=20s

Expand Down
49 changes: 43 additions & 6 deletions admin/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,22 @@ import (
"github.com/percona/pmm/admin/commands"
"github.com/percona/pmm/admin/commands/inventory"
"github.com/percona/pmm/admin/commands/management"
"github.com/percona/pmm/admin/commands/pmm/server"
)

// Commands stores all commands, flags and arguments.
type Commands struct {
// GlobalFlagsGetter supports retrieving GlobalFlags.
type GlobalFlagsGetter interface {
GetGlobalFlags() *flags.GlobalFlags
}

// Check interfaces.
var (
_ GlobalFlagsGetter = &PMMAdminCommands{} //nolint:exhaustruct
_ GlobalFlagsGetter = &PMMCommands{} //nolint:exhaustruct
)

// PMMAdminCommands stores all commands, flags and arguments for the "pmm-admin" binary.
type PMMAdminCommands struct {
flags.GlobalFlags

Status commands.StatusCommand `cmd:"" help:"Show information about local pmm-agent"`
Expand All @@ -48,6 +60,33 @@ type Commands struct {
Version commands.VersionCommand `cmd:"" help:"Print version"`
}

// Run function is a top-level function which handles running all commands
// in a standard way based on the interface they implement.
func (c *PMMAdminCommands) Run(ctx *kong.Context, globals *flags.GlobalFlags) error {
return run(ctx, globals)
}

func (c *PMMAdminCommands) GetGlobalFlags() *flags.GlobalFlags {
return &c.GlobalFlags
}

// PMMCommands stores all commands, flags and arguments for the "pmm" binary.
type PMMCommands struct {
flags.GlobalFlags

Server server.BaseCommand `cmd:"" help:"PMM server related commands"`
}

func (c *PMMCommands) GetGlobalFlags() *flags.GlobalFlags {
return &c.GlobalFlags
}

// Run function is a top-level function which handles running all commands
// in a standard way based on the interface they implement.
func (c *PMMCommands) Run(ctx *kong.Context, globals *flags.GlobalFlags) error {
return run(ctx, globals)
}

// CmdRunner represents a command to be run without arguments.
type CmdRunner interface {
RunCmd() (commands.Result, error)
Expand All @@ -63,9 +102,7 @@ type CmdWithContextRunner interface {
RunCmdWithContext(context.Context, *flags.GlobalFlags) (commands.Result, error)
}

// Run function is a top-level function which handles running all commands
// in a standard way based on the interface they implement.
func (c *Commands) Run(ctx *kong.Context, globals *flags.GlobalFlags) error {
func run(ctx *kong.Context, globals *flags.GlobalFlags) error {
var res commands.Result
var err error

Expand All @@ -82,7 +119,7 @@ func (c *Commands) Run(ctx *kong.Context, globals *flags.GlobalFlags) error {
panic("The command does not implement RunCmd()")
}

return printResponse(&c.GlobalFlags, res, err)
return printResponse(globals, res, err)
}

func printResponse(opts *flags.GlobalFlags, res commands.Result, err error) error {
Expand Down
78 changes: 56 additions & 22 deletions admin/main.go → admin/cmd/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package main
// Package cmd holds common logic used by commands
package cmd

import (
"context"
Expand All @@ -28,6 +29,7 @@ import (

"github.com/percona/pmm/admin/agentlocal"
"github.com/percona/pmm/admin/cli"
"github.com/percona/pmm/admin/cli/flags"
"github.com/percona/pmm/admin/commands"
"github.com/percona/pmm/admin/commands/base"
"github.com/percona/pmm/admin/commands/management"
Expand All @@ -36,7 +38,49 @@ import (
"github.com/percona/pmm/version"
)

func main() {
// Bootstrap is used to initialize the application.
func Bootstrap(opts any) {
var kongCtx *kong.Context
var parsedOpts any

switch o := opts.(type) {
case cli.PMMAdminCommands:
kongCtx = kong.Parse(&o, getDefaultKongOptions("pmm-admin")...)
parsedOpts = &o
case cli.PMMCommands:
kongCtx = kong.Parse(&o, getDefaultKongOptions("pmm")...)
parsedOpts = &o
}

f, ok := parsedOpts.(cli.GlobalFlagsGetter)
if !ok {
logrus.Panic("Cannot assert parsedOpts to GlobalFlagsGetter")
}

globalFlags := f.GetGlobalFlags()

configureLogger(globalFlags)
finishBootstrap(globalFlags)

err := kongCtx.Run(globalFlags)
processFinalError(err, bool(globalFlags.JSON))
}

func configureLogger(opts *flags.GlobalFlags) {
logrus.SetFormatter(&logger.TextFormatter{}) // with levels and timestamps for debug and trace
if opts.JSON {
logrus.SetFormatter(&logrus.JSONFormatter{}) //nolint:exhaustruct // with levels and timestamps always present
}
if opts.EnableDebug {
logrus.SetLevel(logrus.DebugLevel)
}
if opts.EnableTrace {
logrus.SetLevel(logrus.TraceLevel)
logrus.SetReportCaller(true) // https://github.com/sirupsen/logrus/issues/954
}
}

func getDefaultKongOptions(appName string) []kong.Option {
// Detect defaults
nodeinfo := nodeinfo.Get()
nodeTypeDefault := "generic"
Expand All @@ -62,10 +106,8 @@ func main() {
management.MongodbQuerySourceNone,
}

// Configure CLI
var opts cli.Commands
kongCtx := kong.Parse(&opts,
kong.Name("pmm-admin"),
return []kong.Option{
kong.Name(appName),
kong.Description(fmt.Sprintf("Version %s", version.Version)),
kong.UsageOnError(),
kong.ConfigureHelp(kong.HelpOptions{
Expand All @@ -87,20 +129,11 @@ func main() {
"mongoDbQuerySourceDefault": mongoDBQuerySources[0],
"externalDefaultServiceName": management.DefaultServiceNameSuffix,
"externalDefaultGroupExporter": management.DefaultGroupExternalExporter,
})

logrus.SetFormatter(&logger.TextFormatter{}) // with levels and timestamps for debug and trace
if opts.JSON {
logrus.SetFormatter(&logrus.JSONFormatter{}) // with levels and timestamps always present
}
if opts.EnableDebug {
logrus.SetLevel(logrus.DebugLevel)
}
if opts.EnableTrace {
logrus.SetLevel(logrus.TraceLevel)
logrus.SetReportCaller(true) // https://github.com/sirupsen/logrus/issues/954
},
}
}

func finishBootstrap(globalFlags *flags.GlobalFlags) {
ctx, cancel := context.WithCancel(context.Background())

// handle termination signals
Expand All @@ -113,18 +146,19 @@ func main() {
cancel()
}()

agentlocal.SetTransport(ctx, opts.EnableDebug || opts.EnableTrace, opts.PMMAgentListenPort)
agentlocal.SetTransport(ctx, globalFlags.EnableDebug || globalFlags.EnableTrace, globalFlags.PMMAgentListenPort)

// pmm-admin status command don't connect to PMM Server.
if commands.SetupClientsEnabled {
base.SetupClients(ctx, &opts.GlobalFlags)
base.SetupClients(ctx, globalFlags)
}

commands.CLICtx = ctx
}

err := kongCtx.Run(&opts.GlobalFlags)
func processFinalError(err error, isJSON bool) {
if err != nil {
if opts.JSON {
if isJSON {
b, jErr := json.Marshal(err.Error())
if jErr != nil {
logrus.Infof("Error: %#v.", err)
Expand Down
24 changes: 24 additions & 0 deletions admin/cmd/pmm-admin/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2019 Percona LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/percona/pmm/admin/cli"
"github.com/percona/pmm/admin/cmd"
)

func main() {
cmd.Bootstrap(cli.PMMAdminCommands{}) //nolint:exhaustruct
}
File renamed without changes.
24 changes: 24 additions & 0 deletions admin/cmd/pmm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2019 Percona LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/percona/pmm/admin/cli"
"github.com/percona/pmm/admin/cmd"
)

func main() {
cmd.Bootstrap(cli.PMMCommands{}) //nolint:exhaustruct
}
29 changes: 29 additions & 0 deletions admin/commands/pmm/server/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2019 Percona LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package server holds the "pmm server" command
package server

import "github.com/percona/pmm/admin/commands"

// BaseCommand is used by Kong for CLI flags and commands and holds all server commands.
type BaseCommand struct {
Install InstallCommand `cmd:"" help:"Install PMM server"`
}

// BeforeApply is run before the command is applied.
func (cmd *BaseCommand) BeforeApply() error {
commands.SetupClientsEnabled = false
return nil
}
35 changes: 35 additions & 0 deletions admin/commands/pmm/server/install.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2019 Percona LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package server

import "github.com/percona/pmm/admin/commands"

// InstallCommand is used by Kong for CLI flags and commands.
type InstallCommand struct{}

type installResult struct{}

// Result is a command run result.
func (res *installResult) Result() {}

// String stringifies command result.
func (res *installResult) String() string {
return "works"
}

// RunCmd runs install command.
func (c *InstallCommand) RunCmd() (commands.Result, error) {
return &installResult{}, nil
}

0 comments on commit a4e879e

Please sign in to comment.