Skip to content

Commit

Permalink
Merge pull request juju#16076 from barrettj12/merge-3.2-3.3-20230811
Browse files Browse the repository at this point in the history
juju#16076

Merges the following patches:
- juju#16074
- juju#16073
- juju#16059
- juju#16071
- juju#16064
- juju#16066
- juju#16056

### Conflicts
None.
  • Loading branch information
jujubot authored Aug 11, 2023
2 parents 3a137c3 + 6a03f70 commit f3c2ea8
Show file tree
Hide file tree
Showing 17 changed files with 266 additions and 203 deletions.
173 changes: 114 additions & 59 deletions cmd/juju/cloud/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ package cloud

import (
"fmt"
"sort"
"strings"

"github.com/juju/cmd/v3"
"github.com/juju/errors"
Expand Down Expand Up @@ -82,9 +84,10 @@ func (c *showCloudCommand) cloudAPI() (showCloudAPI, error) {

func (c *showCloudCommand) SetFlags(f *gnuflag.FlagSet) {
c.OptionalControllerCommand.SetFlags(f)
// We only support yaml for display purposes.
c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{
"yaml": cmd.FormatYaml,
c.out.AddFlags(f, "display", map[string]cmd.Formatter{
"yaml": cmd.FormatYaml,
"json": cmd.FormatJson,
"display": cmd.FormatYaml,
})
f.BoolVar(&c.includeConfig, "include-config", false, "Print available config option details specific to the specified cloud")
}
Expand Down Expand Up @@ -121,15 +124,17 @@ func (c *showCloudCommand) Run(ctxt *cmd.Context) error {
if err := c.MaybePrompt(ctxt, fmt.Sprintf("show cloud %q from", c.CloudName)); err != nil {
return errors.Trace(err)
}

var (
localCloud *CloudDetails
localErr error
displayErr error
outputs []CloudOutput
)

if c.Client {
localCloud, localErr = c.getLocalCloud()
}

var displayErr error
if c.ControllerName != "" {
remoteCloud, remoteErr := c.getControllerCloud()
showRemoteConfig := c.includeConfig
Expand All @@ -141,74 +146,108 @@ func (c *showCloudCommand) Run(ctxt *cmd.Context) error {
// config once after the local cloud information.
showRemoteConfig = showRemoteConfig && localCloud.CloudType != remoteCloud.CloudType
}
if remoteCloud != nil {
if err := c.displayCloud(ctxt, remoteCloud, fmt.Sprintf("Cloud %q from controller %q:\n", c.CloudName, c.ControllerName), showRemoteConfig, remoteErr); err != nil {
ctxt.Infof("ERROR %v", err)
displayErr = cmd.ErrSilent
}

if remoteErr != nil {
ctxt.Infof("ERROR %v", remoteErr)
displayErr = cmd.ErrSilent
} else if remoteCloud != nil {
outputs = append(outputs, c.displayCloud(
remoteCloud,
c.CloudName,
fmt.Sprintf("Cloud %q from controller %q", c.CloudName, c.ControllerName),
showRemoteConfig,
))
} else {
if remoteErr != nil {
ctxt.Infof("ERROR %v", remoteErr)
displayErr = cmd.ErrSilent
} else {
ctxt.Infof("No cloud %q exists on the controller.", c.CloudName)
}
ctxt.Infof("No cloud %q exists on the controller.", c.CloudName)
}
}
if c.Client {
if localCloud != nil {
if err := c.displayCloud(ctxt, localCloud, fmt.Sprintf("\nClient cloud %q:\n", c.CloudName), c.includeConfig, localErr); err != nil {
ctxt.Infof("ERROR %v", err)
displayErr = cmd.ErrSilent
}
if localErr != nil {
ctxt.Infof("ERROR %v", localErr)
displayErr = cmd.ErrSilent
} else if localCloud != nil {
outputs = append(outputs, c.displayCloud(
localCloud,
c.CloudName,
fmt.Sprintf("Client cloud %q", c.CloudName),
c.includeConfig,
))
} else {
if localErr != nil {
ctxt.Infof("ERROR %v", localErr)
displayErr = cmd.ErrSilent
} else {
ctxt.Infof("No cloud %q exists on this client.", c.CloudName)
}
ctxt.Infof("No cloud %q exists on this client.", c.CloudName)
}
}

// It's possible that a config was desired but was not display because the
// remote cloud erred out.
if c.includeConfig && !c.configDisplayed && localErr == nil {
if err := c.displayConfig(ctxt, localCloud.CloudType); err != nil {
return err
if c.includeConfig && !c.configDisplayed && localCloud != nil && localErr == nil {
outputs = append(outputs, CloudOutput{
Name: c.CloudName,
Summary: fmt.Sprintf("Client cloud %q", c.CloudName),
Config: getCloudConfigDetails(localCloud.CloudType),
})
}

if len(outputs) == 0 {
return displayErr
}

switch c.out.Name() {
case "display":
for _, output := range outputs {
var written bool
if output.CloudDetails != nil {
fmt.Fprintf(ctxt.Stdout, "%s:\n\n", output.Summary)

if err := c.out.Write(ctxt, output.CloudDetails); err != nil {
return errors.Trace(err)
}
written = true
}

if len(output.Config) > 0 {
fmt.Fprintln(ctxt.Stdout)
fmt.Fprintf(ctxt.Stdout, "The available config options specific to %s clouds are:\n", output.CloudType)

if err := c.out.Write(ctxt, output.Config); err != nil {
return errors.Trace(err)
}
written = true
}
if written && len(outputs) > 1 {
fmt.Fprintln(ctxt.Stdout)
}
}
case "yaml":
for _, output := range outputs {
if err := c.out.Write(ctxt, output); err != nil {
return errors.Trace(err)
}
if len(outputs) > 1 {
fmt.Fprintln(ctxt.Stdout, "---")
}
}
case "json":
if err := c.out.Write(ctxt, outputs); err != nil {
return errors.Trace(err)
}
}

return displayErr
}

func (c *showCloudCommand) displayCloud(ctxt *cmd.Context, aCloud *CloudDetails, msg string, includeConfig bool, cloudErr error) error {
if cloudErr != nil {
return cloudErr
}
fmt.Fprintln(ctxt.Stdout, msg)
func (c *showCloudCommand) displayCloud(aCloud *CloudDetails, name, summary string, includeConfig bool) CloudOutput {
aCloud.CloudType = displayCloudType(aCloud.CloudType)
if err := c.out.Write(ctxt, aCloud); err != nil {
return err
}
var config map[string]any
if includeConfig {
return c.displayConfig(ctxt, aCloud.CloudType)
}
return nil
}

func (c *showCloudCommand) displayConfig(ctxt *cmd.Context, cloudType string) error {
config := getCloudConfigDetails(cloudType)
if len(config) > 0 {
fmt.Fprintln(
ctxt.Stdout,
fmt.Sprintf("\nThe available config options specific to %s clouds are:", cloudType))
if err := c.out.Write(ctxt, config); err != nil {
return err
}
config = getCloudConfigDetails(aCloud.CloudType)
c.configDisplayed = true
}
return nil
return CloudOutput{
Name: name,
Summary: summary,
CloudDetails: aCloud,
Config: config,
}
}

func (c *showCloudCommand) getControllerCloud() (*CloudDetails, error) {
Expand All @@ -232,11 +271,27 @@ func (c *showCloudCommand) getLocalCloud() (*CloudDetails, error) {
}
cloud, ok := details[c.CloudName]
if !ok {
return nil, errors.NotFoundf("cloud %q, %v", c.CloudName, details)
alternatives := make([]string, 0, len(details))
for name := range details {
alternatives = append(alternatives, name)
}
if len(alternatives) == 0 {
return nil, errors.NotFoundf("cloud %s", c.CloudName)
}
sort.Strings(alternatives)
names := strings.Join(alternatives, "\n - ")
return nil, errors.NewNotFound(nil, fmt.Sprintf("cloud %s not found, possible alternative clouds:\n\n - %s", c.CloudName, names))
}
return cloud, nil
}

type CloudOutput struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Summary string `yaml:"summary,omitempty" json:"summary,omitempty"`
*CloudDetails `yaml:",inline" json:",inline"`
Config map[string]any `yaml:"cloud-config,omitempty" json:"cloud-config,omitempty"`
}

// RegionDetails holds region details.
type RegionDetails struct {
Name string `yaml:"-" json:"-"`
Expand Down Expand Up @@ -268,7 +323,7 @@ type CloudDetails struct {
Regions yaml.MapSlice `yaml:"regions,omitempty" json:"-"`
// Regions map is for json marshalling where format is important but not order.
RegionsMap map[string]RegionDetails `yaml:"-" json:"regions,omitempty"`
Config map[string]interface{} `yaml:"config,omitempty" json:"config,omitempty"`
Config map[string]any `yaml:"config,omitempty" json:"config,omitempty"`
RegionConfig jujucloud.RegionConfig `yaml:"region-config,omitempty" json:"region-config,omitempty"`
CACredentials []string `yaml:"ca-credentials,omitempty" json:"ca-credentials,omitempty"`
Users map[string]CloudUserInfo `json:"users,omitempty" yaml:"users,omitempty"`
Expand Down Expand Up @@ -309,7 +364,7 @@ func makeCloudDetailsForUser(store jujuclient.CredentialGetter, cloud cloudapi.C
if region.StorageEndpoint != result.StorageEndpoint {
r.StorageEndpoint = region.StorageEndpoint
}
result.Regions = append(result.Regions, yaml.MapItem{r.Name, r})
result.Regions = append(result.Regions, yaml.MapItem{Key: r.Name, Value: r})
result.RegionsMap[region.Name] = r
}
if cred, err := store.CredentialForCloud(cloud.Name); err == nil {
Expand All @@ -325,15 +380,15 @@ func makeCloudDetailsForUser(store jujuclient.CredentialGetter, cloud cloudapi.C
return result
}

func getCloudConfigDetails(cloudType string) map[string]interface{} {
func getCloudConfigDetails(cloudType string) map[string]any {
// providerSchema has all config options, including their descriptions
// and types.
providerSchema, err := common.CloudSchemaByType(cloudType)
if err != nil {
// Some providers do not implement the ProviderSchema interface.
return nil
}
specifics := make(map[string]interface{})
specifics := make(map[string]any)
ps, err := common.ProviderConfigSchemaSourceByType(cloudType)
if err != nil {
// Some providers do not implement the ConfigSchema interface.
Expand All @@ -347,7 +402,7 @@ func getCloudConfigDetails(cloudType string) map[string]interface{} {
}
specifics[attr] = common.PrintConfigSchema{
Description: providerSchema[attr].Description,
Type: fmt.Sprintf("%s", providerSchema[attr].Type),
Type: string(providerSchema[attr].Type),
}
}
return specifics
Expand Down
6 changes: 1 addition & 5 deletions cmd/juju/cloud/show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ func (s *showSuite) assertShowLocal(c *gc.C, expectedOutput string) {

func (s *showSuite) TestShowLocal(c *gc.C) {
s.assertShowLocal(c, `
Client cloud "aws-china":
defined: public
Expand All @@ -76,7 +75,6 @@ regions:
func (s *showSuite) TestShowLocalWithDefaultCloud(c *gc.C) {
s.store.Credentials["aws-china"] = jujucloud.CloudCredential{DefaultRegion: "cn-north-1"}
s.assertShowLocal(c, `
Client cloud "aws-china":
defined: public
Expand Down Expand Up @@ -221,6 +219,7 @@ regions:
endpoint: https://ec2.cn-north-1.amazonaws.com.cn
cn-northwest-1:
endpoint: https://ec2.cn-northwest-1.amazonaws.com.cn
`[1:])
}

Expand All @@ -245,7 +244,6 @@ clouds:
c.Assert(err, jc.ErrorIsNil)
out := cmdtesting.Stdout(ctx)
c.Assert(out, gc.Equals, `
Client cloud "homestack":
defined: local
Expand Down Expand Up @@ -308,7 +306,6 @@ clouds:
c.Assert(err, jc.ErrorIsNil)
out := cmdtesting.Stdout(ctx)
c.Assert(out, gc.Equals, strings.Join([]string{`
Client cloud "homestack":
defined: local
Expand Down Expand Up @@ -360,7 +357,6 @@ clouds:
`[1:]

var resultWithCert = `
Client cloud "homestack":
defined: local
Expand Down
7 changes: 1 addition & 6 deletions cmd/jujud/agent/agenttest/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ func InstallFakeEnsureMongo(suite patchingSuite, dataDir string) *FakeEnsureMong
f := &FakeEnsureMongo{}
suite.PatchValue(&mongo.CurrentReplicasetConfig, f.CurrentConfig)
suite.PatchValue(&cmdutil.EnsureMongoServerInstalled, f.EnsureMongo)
suite.PatchValue(&cmdutil.EnsureMongoServerStarted, f.EnsureMongoStarted)
ensureParams := cmdutil.NewEnsureMongoParams
suite.PatchValue(&cmdutil.NewEnsureMongoParams, func(agentConfig agent.Config) (mongo.EnsureServerParams, error) {
params, err := ensureParams(agentConfig)
Expand Down Expand Up @@ -88,7 +87,7 @@ func (f *FakeEnsureMongo) CurrentConfig(*mgo.Session) (*replicaset.Config, error
}, nil
}

func (f *FakeEnsureMongo) EnsureMongo(args mongo.EnsureServerParams) error {
func (f *FakeEnsureMongo) EnsureMongo(ctx context.Context, args mongo.EnsureServerParams) error {
f.EnsureCount++
f.DataDir, f.OplogSize = args.DataDir, args.OplogSize
f.Info = controller.StateServingInfo{
Expand All @@ -103,10 +102,6 @@ func (f *FakeEnsureMongo) EnsureMongo(args mongo.EnsureServerParams) error {
return f.Err
}

func (f *FakeEnsureMongo) EnsureMongoStarted(snapChannel string) error {
return f.Err
}

func (f *FakeEnsureMongo) InitiateMongo(p peergrouper.InitiateMongoParams) error {
f.InitiateCount++
f.InitiateParams = p
Expand Down
Loading

0 comments on commit f3c2ea8

Please sign in to comment.