Skip to content
This repository has been archived by the owner on Mar 4, 2024. It is now read-only.

Commit

Permalink
EVEREST-593: Support for password reset (#221)
Browse files Browse the repository at this point in the history
- Generate password during installation
  • Loading branch information
Michal Kralik authored Nov 28, 2023
1 parent f86629d commit a9add28
Show file tree
Hide file tree
Showing 10 changed files with 294 additions and 9 deletions.
1 change: 1 addition & 0 deletions cli-tests/tests/flow/all-operators.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ test.describe('Everest CLI install', async () => {
'percona-server-mongodb-operator operator has been installed',
'percona-postgresql-operator operator has been installed',
'everest-operator operator has been installed',
'Your new password is',
]);
});

Expand Down
34 changes: 34 additions & 0 deletions commands/password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// percona-everest-cli
// Copyright (C) 2023 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 commands ...
package commands

import (
"github.com/spf13/cobra"
"go.uber.org/zap"

"github.com/percona/percona-everest-cli/commands/password"
)

func newPasswordCmd(l *zap.SugaredLogger) *cobra.Command {
cmd := &cobra.Command{
Use: "password",
}

cmd.AddCommand(password.NewResetCmd(l))

return cmd
}
78 changes: 78 additions & 0 deletions commands/password/reset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// percona-everest-cli
// Copyright (C) 2023 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 password holds commands for password command.
package password

import (
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.uber.org/zap"

"github.com/percona/percona-everest-cli/pkg/output"
"github.com/percona/percona-everest-cli/pkg/password"
)

// NewResetCmd returns a new versions command.
func NewResetCmd(l *zap.SugaredLogger) *cobra.Command {
cmd := &cobra.Command{
Use: "reset",
Run: func(cmd *cobra.Command, args []string) {
initResetViperFlags(cmd)

c, err := parseResetConfig()
if err != nil {
os.Exit(1)
}

command, err := password.NewReset(*c, l)
if err != nil {
output.PrintError(err, l)
os.Exit(1)
}

res, err := command.Run(cmd.Context())
if err != nil {
output.PrintError(err, l)
os.Exit(1)
}

output.PrintOutput(cmd, l, res)
},
}

initResetFlags(cmd)

return cmd
}

func initResetFlags(cmd *cobra.Command) {
cmd.Flags().StringP("kubeconfig", "k", "~/.kube/config", "Path to a kubeconfig")
cmd.Flags().String("namespace", "percona-everest", "Namespace where Percona Everest is deployed")
}

func initResetViperFlags(cmd *cobra.Command) {
viper.BindEnv("kubeconfig") //nolint:errcheck,gosec
viper.BindPFlag("kubeconfig", cmd.Flags().Lookup("kubeconfig")) //nolint:errcheck,gosec
viper.BindPFlag("namespace", cmd.Flags().Lookup("namespace")) //nolint:errcheck,gosec
}

func parseResetConfig() (*password.ResetConfig, error) {
c := &password.ResetConfig{}
err := viper.Unmarshal(c)
return c, err
}
1 change: 1 addition & 0 deletions commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func NewRootCmd(l *zap.SugaredLogger) *cobra.Command {
// rootCmd.AddCommand(newProvisionCmd(l))
// rootCmd.AddCommand(newListCmd(l))
rootCmd.AddCommand(newDeleteCmd(l))
rootCmd.AddCommand(newPasswordCmd(l))
rootCmd.AddCommand(newVersionCmd(l))
rootCmd.AddCommand(newUpgradeCmd(l))
rootCmd.AddCommand(newUninstallCmd(l))
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.21

require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/dchest/uniuri v1.2.0
github.com/go-logr/zapr v1.3.0
github.com/hashicorp/go-version v1.6.0
github.com/operator-framework/api v0.19.0
Expand All @@ -14,6 +15,7 @@ require (
github.com/spf13/viper v1.17.0
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.26.0
golang.org/x/crypto v0.14.0
golang.org/x/sync v0.5.0
gopkg.in/yaml.v3 v3.0.1
gotest.tools v2.2.0+incompatible
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dchest/uniuri v1.2.0 h1:koIcOUdrTIivZgSLhHQvKgqdWZq5d7KdMEWF1Ud6+5g=
github.com/dchest/uniuri v1.2.0/go.mod h1:fSzm4SLHzNZvWLvWJew423PhAzkpNQYq+uNLq4kxhkY=
github.com/docker/cli v23.0.1+incompatible h1:LRyWITpGzl2C9e9uGxzisptnxAn1zfZKXy13Ul2Q5oM=
github.com/docker/cli v23.0.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8=
Expand Down Expand Up @@ -491,6 +493,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
Expand Down
18 changes: 14 additions & 4 deletions pkg/everest/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,16 @@ func NewEverest(everestClient *client.Client) *Everest {
}

// NewEverestFromURL returns a new Everest from a provided URL.
func NewEverestFromURL(url string) (*Everest, error) {
everestCl, err := client.NewClient(fmt.Sprintf("%s/v1", url))
func NewEverestFromURL(url, everestPwd string) (*Everest, error) {
everestCl, err := client.NewClient(
fmt.Sprintf("%s/v1", url),
client.WithRequestEditorFn(func(ctx context.Context, req *http.Request) error {
req.Header.Add("Authentication", fmt.Sprintf("Bearer %s", everestPwd))
return nil
}),
)
if err != nil {
return nil, errors.Join(err, errors.New("could not initialize everest client"))
return nil, errors.Join(err, errors.New("could not initialize Everest client"))
}
return NewEverest(everestCl), nil
}
Expand All @@ -57,7 +63,7 @@ func NewEverestFromURL(url string) (*Everest, error) {
// Learn more https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster-services/#manually-constructing-apiserver-proxy-urls
//
// This client must be used only for provisioning only.
func NewProxiedEverest(config *rest.Config, namespace string) (*Everest, error) {
func NewProxiedEverest(config *rest.Config, namespace, everestPwd string) (*Everest, error) {
host, err := url.Parse(config.Host)
if err != nil {
return nil, err
Expand All @@ -68,6 +74,10 @@ func NewProxiedEverest(config *rest.Config, namespace string) (*Everest, error)
host,
url.PathEscape(namespace),
),
client.WithRequestEditorFn(func(ctx context.Context, req *http.Request) error {
req.Header.Add("Authentication", fmt.Sprintf("Bearer %s", everestPwd))
return nil
}),
)
if err != nil {
return nil, err
Expand Down
44 changes: 39 additions & 5 deletions pkg/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/percona/percona-everest-cli/commands/common"
everestClient "github.com/percona/percona-everest-cli/pkg/everest/client"
"github.com/percona/percona-everest-cli/pkg/kubernetes"
"github.com/percona/percona-everest-cli/pkg/password"
)

// Install implements the main logic for commands.
Expand Down Expand Up @@ -161,11 +162,20 @@ func (o *Install) Run(ctx context.Context) error {
if err := o.provisionNamespace(); err != nil {
return err
}

if err := o.configureEverestConnector(); err != nil {
pwd, err := o.generatePassword(ctx)
if err != nil {
return err
}
if err := o.configureEverestConnector(pwd.Password); err != nil {
return err
}
if err := o.performProvisioning(ctx); err != nil {
return err
}
return o.performProvisioning(ctx)

o.l.Info(pwd)

return nil
}

func (o *Install) populateConfig() error {
Expand Down Expand Up @@ -320,8 +330,8 @@ func (o *Install) createPMMMonitoringInstance(ctx context.Context, name, url, us
return nil
}

func (o *Install) configureEverestConnector() error {
e, err := everestClient.NewProxiedEverest(o.kubeClient.Config(), o.config.Namespace)
func (o *Install) configureEverestConnector(everestPwd string) error {
e, err := everestClient.NewProxiedEverest(o.kubeClient.Config(), o.config.Namespace, everestPwd)
if err != nil {
return err
}
Expand Down Expand Up @@ -600,6 +610,30 @@ func (o *Install) installOperator(ctx context.Context, channel, operatorName str
}
}

func (o *Install) generatePassword(ctx context.Context) (*password.ResetResponse, error) {
o.l.Info("Creating password for Everest")

r, err := password.NewReset(
password.ResetConfig{
KubeconfigPath: o.config.KubeconfigPath,
Namespace: o.config.Namespace,
},
o.l,
)
if err != nil {
return nil, errors.Join(err, errors.New("could not initialize reset password"))
}

res, err := r.Run(ctx)
if err != nil {
return nil, errors.Join(err, errors.New("could not create password"))
}

o.l.Debug(res)

return res, nil
}

func (o *Install) restartEverestOperatorPod(ctx context.Context) error {
return o.kubeClient.RestartEverest(ctx, "everest-operator", o.config.Namespace)
}
5 changes: 5 additions & 0 deletions pkg/kubernetes/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ func (k *Kubernetes) ListSecrets(ctx context.Context) (*corev1.SecretList, error
return k.client.ListSecrets(ctx)
}

// SetSecret creates or updates an existing secret.
func (k *Kubernetes) SetSecret(secret *corev1.Secret) error {
return k.client.ApplyObject(secret)
}

// CreatePMMSecret creates pmm secret in kubernetes.
func (k *Kubernetes) CreatePMMSecret(namespace, secretName string, secrets map[string][]byte) error {
secret := &corev1.Secret{ //nolint: exhaustruct
Expand Down
Loading

0 comments on commit a9add28

Please sign in to comment.