Skip to content

Commit

Permalink
[FEATURE] Add config command that displays local or remote config (#1845
Browse files Browse the repository at this point in the history
)

* [FEATURE] Add config command that displays local or remote config

Signed-off-by: Augustin Husson <husson.augustin@gmail.com>

* display only public config

Signed-off-by: Augustin Husson <husson.augustin@gmail.com>

---------

Signed-off-by: Augustin Husson <husson.augustin@gmail.com>
  • Loading branch information
Nexucis committed Mar 28, 2024
1 parent fabab37 commit 926878b
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 4 deletions.
2 changes: 2 additions & 0 deletions cmd/percli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"os"

"github.com/perses/perses/internal/cli/cmd/apply"
"github.com/perses/perses/internal/cli/cmd/conf"
"github.com/perses/perses/internal/cli/cmd/dac"
"github.com/perses/perses/internal/cli/cmd/describe"
"github.com/perses/perses/internal/cli/cmd/get"
Expand Down Expand Up @@ -45,6 +46,7 @@ func newRootCommand() *cobra.Command {

// The list of supported commands
cmd.AddCommand(apply.NewCMD())
cmd.AddCommand(conf.NewCMD())
cmd.AddCommand(dac.NewCMD())
cmd.AddCommand(describe.NewCMD())
cmd.AddCommand(get.NewCMD())
Expand Down
91 changes: 91 additions & 0 deletions internal/cli/cmd/conf/conf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2024 The Perses Authors
// 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 conf

import (
"fmt"
"io"

persesCMD "github.com/perses/perses/internal/cli/cmd"
"github.com/perses/perses/internal/cli/config"
"github.com/perses/perses/internal/cli/opt"
"github.com/perses/perses/internal/cli/output"
"github.com/perses/perses/pkg/client/api"
"github.com/spf13/cobra"
)

type option struct {
persesCMD.Option
opt.OutputOption
writer io.Writer
online bool
apiClient api.ClientInterface
}

func (o *option) Complete(args []string) error {
if len(args) > 0 {
return fmt.Errorf("no args are supported by the command 'config'")
}
if outputErr := o.OutputOption.Complete(); outputErr != nil {
return outputErr
}
if o.online {
apiClient, err := config.Global.GetAPIClient()
if err != nil {
return err
}
o.apiClient = apiClient
}
return nil
}

func (o *option) Validate() error {
return nil
}

func (o *option) Execute() error {
if !o.online {
return output.Handle(o.writer, o.Output, config.NewPublicConfig(config.Global))
}
cfg, err := o.apiClient.Config()
if err != nil {
return err
}
return output.Handle(o.writer, o.Output, cfg)
}

func (o *option) SetWriter(writer io.Writer) {
o.writer = writer
}

func NewCMD() *cobra.Command {
o := &option{}
cmd := &cobra.Command{
Use: "config",
Short: "display local or remote config",
Example: `
# Display local config in json
percli config --output=json
# Display remote config in yaml
percli config --online --output=yaml
`,
RunE: func(cmd *cobra.Command, args []string) error {
return persesCMD.Run(o, cmd, args)
},
}
opt.AddOutputFlags(cmd, &o.OutputOption)
cmd.Flags().BoolVar(&o.online, "online", o.online, "When enable, it can request the API to display the remote config")
return cmd
}
54 changes: 54 additions & 0 deletions internal/cli/cmd/conf/conf_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2024 The Perses Authors
// 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 conf

import (
"testing"

cmdTest "github.com/perses/perses/internal/cli/test"
fakeapi "github.com/perses/perses/pkg/client/fake/api"
)

func TestConfigCMD(t *testing.T) {
testSuite := []cmdTest.Suite{
{
Title: "empty args",
Args: []string{},
IsErrorExpected: false,
ExpectedMessage: `dac:
output_folder: built
`,
},
{
Title: "not connected to any API",
Args: []string{"--online"},
IsErrorExpected: true,
ExpectedMessage: "you are not connected to any API",
},
{
Title: "remote config",
Args: []string{"--online"},
IsErrorExpected: false,
APIClient: fakeapi.New(),
ExpectedMessage: `security:
readonly: false
enable_auth: true
deactivate_front: false
`,
},
}
cmdTest.ExecuteSuiteTest(t, NewCMD, testSuite)
}
28 changes: 24 additions & 4 deletions internal/cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,37 @@ func Init(configPath string) {
}
}

// PublicConfig should be only used when displaying the config to the client
type PublicConfig struct {
RestClientConfig perseshttp.PublicRestConfigClient `json:"rest_client_config,omitempty" yaml:"rest_client_config,omitempty"`
Project string `json:"project,omitempty" yaml:"project,omitempty"`
RefreshToken secret.Hidden `json:"refresh_token,omitempty" yaml:"refresh_token,omitempty"`
Dac Dac `json:"dac,omitempty" yaml:"dac,omitempty"`
}

func NewPublicConfig(cfg *Config) *PublicConfig {
if cfg == nil {
return nil
}
return &PublicConfig{
RestClientConfig: *perseshttp.NewPublicRestConfigClient(&cfg.RestClientConfig),
Project: cfg.Project,
RefreshToken: secret.Hidden(cfg.RefreshToken),
Dac: cfg.Dac,
}
}

// Dac wraps the configuration related to Dashboard-as-Code
type Dac struct {
// outputFolder is the folder where the dac-generated files are stored
OutputFolder string `json:"output_folder,omitempty" yaml:"output_folder,omitempty"`
}

type Config struct {
RestClientConfig perseshttp.RestConfigClient `json:"rest_client_config"`
Project string `json:"project,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
Dac Dac `json:"dac,omitempty"`
RestClientConfig perseshttp.RestConfigClient `json:"rest_client_config,omitempty" yaml:"rest_client_config,omitempty"`
Project string `json:"project,omitempty" yaml:"project,omitempty"`
RefreshToken string `json:"refresh_token,omitempty" yaml:"refresh_token,omitempty"`
Dac Dac `json:"dac,omitempty" yaml:"dac,omitempty"`
filePath string
apiClient api.ClientInterface
}
Expand Down
24 changes: 24 additions & 0 deletions pkg/client/perseshttp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,30 @@ import (

const connectionTimeout = 30 * time.Second

// PublicRestConfigClient is the struct that should be used when printing the config
type PublicRestConfigClient struct {
URL *common.URL `json:"url" yaml:"url"`
BasicAuth *secret.PublicBasicAuth `json:"basicAuth,omitempty" yaml:"basicAuth,omitempty"`
// The HTTP authorization credentials for the targets.
Authorization *secret.PublicAuthorization `json:"authorization,omitempty" yaml:"authorization,omitempty"`
// TLSConfig to use to connect to the targets.
TLSConfig *secret.PublicTLSConfig `json:"tlsConfig,omitempty" yaml:"tlsConfig,omitempty"`
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"`
}

func NewPublicRestConfigClient(config *RestConfigClient) *PublicRestConfigClient {
if config == nil {
return nil
}
return &PublicRestConfigClient{
URL: config.URL,
BasicAuth: secret.NewPublicBasicAuth(config.BasicAuth),
Authorization: secret.NewPublicAuthorization(config.Authorization),
TLSConfig: secret.NewPublicTLSConfig(config.TLSConfig),
Headers: config.Headers,
}
}

// RestConfigClient defines all parameters that can be set to customize the RESTClient
type RestConfigClient struct {
URL *common.URL `json:"url" yaml:"url"`
Expand Down

0 comments on commit 926878b

Please sign in to comment.