diff --git a/cmd/juju/application/deployer/deployer.go b/cmd/juju/application/deployer/deployer.go index ac9cc938a21..8209df64849 100644 --- a/cmd/juju/application/deployer/deployer.go +++ b/cmd/juju/application/deployer/deployer.go @@ -266,6 +266,10 @@ func (d *factory) maybeReadLocalBundle() (Deployer, error) { if err != nil { return nil, errors.Annotate(err, "cannot deploy bundle") } + if err = handleUnmarshallError(ds.Parts()); err != nil && !d.force { + return nil, errors.Annotate(err, "cannot deploy bundle, invalid fields") + } + if err := d.validateBundleFlags(); err != nil { return nil, errors.Trace(err) } @@ -284,6 +288,22 @@ func (d *factory) maybeReadLocalBundle() (Deployer, error) { return &localBundle{deployBundle: db}, nil } +func handleUnmarshallError(parts []*charm.BundleDataPart) error { + messages := set.NewStrings() + for _, part := range parts { + if part == nil { + continue + } + if part.UnmarshallError != nil { + messages.Add(part.UnmarshallError.Error()) + } + } + if messages.IsEmpty() { + return nil + } + return errors.New(strings.Join(messages.Values(), "\n")) +} + // newDeployBundle returns the config needed to eventually call // deployBundle.deploy. This is used by all types of bundles to // be deployed diff --git a/cmd/juju/application/deployer/deployer_test.go b/cmd/juju/application/deployer/deployer_test.go index 5759d73620f..1488fb5c0f1 100644 --- a/cmd/juju/application/deployer/deployer_test.go +++ b/cmd/juju/application/deployer/deployer_test.go @@ -235,6 +235,54 @@ func (s *deployerSuite) TestGetDeployerLocalBundle(c *gc.C) { c.Assert(deployer.String(), gc.Equals, fmt.Sprintf("deploy local bundle from: %s", bundlePath)) } +func (s *deployerSuite) TestGetDeployerLocalBundleStrict(c *gc.C) { + defer s.setupMocks(c).Finish() + + _, err := s.testGetDeployerLocalBundleStrict(c, false) + c.Assert(err.Error(), gc.Equals, ("cannot deploy bundle, invalid fields: unmarshal document 0: yaml: unmarshal errors:\n line 3: field descriptn not found in bundle\n line 8: field contstraints not found in applications")) +} + +func (s *deployerSuite) TestGetDeployerLocalBundleStrictUseForce(c *gc.C) { + defer s.setupMocks(c).Finish() + + deployer, err := s.testGetDeployerLocalBundleStrict(c, true) + c.Assert(err, jc.ErrorIsNil) + c.Assert(deployer.String(), gc.Matches, "deploy local bundle from: .*") + +} + +func (s *deployerSuite) testGetDeployerLocalBundleStrict(c *gc.C, force bool) (Deployer, error) { + s.expectFilesystem() + + cfg := s.basicDeployerConfig() + cfg.Series = "bionic" + cfg.FlagSet = &gnuflag.FlagSet{} + cfg.Force = force + s.expectModelType() + + content := ` + series: xenial + descriptn: bundle to fail strict parsing + applications: + wordpress: + charm: wordpress + num_units: 1 + contstraints: "mem=8G" + mysql: + charm: mysql + num_units: 2 + relations: + - ["wordpress:db", "mysql:server"] +` + + bundlePath := s.makeBundleDir(c, content) + s.expectStat(bundlePath, nil) + cfg.CharmOrBundle = bundlePath + + factory := s.newDeployerFactory() + return factory.GetDeployer(cfg, s.modelConfigGetter, s.resolver) +} + func (s *deployerSuite) TestGetDeployerCharmStoreBundle(c *gc.C) { bundle := charm.MustParseURL("cs:test-bundle") cfg := s.basicDeployerConfig() diff --git a/go.mod b/go.mod index 280ee23d4c3..ec7d0b591e4 100644 --- a/go.mod +++ b/go.mod @@ -51,7 +51,7 @@ require ( github.com/im7mortal/kmutex v1.0.1 github.com/juju/ansiterm v1.0.0 github.com/juju/blobstore/v2 v2.0.0 - github.com/juju/charm/v8 v8.0.1 + github.com/juju/charm/v8 v8.0.2 github.com/juju/charmrepo/v6 v6.0.2 github.com/juju/clock v1.0.0 github.com/juju/cmd/v3 v3.0.0 diff --git a/go.sum b/go.sum index fdffae5d146..29554a2c75c 100644 --- a/go.sum +++ b/go.sum @@ -496,8 +496,8 @@ github.com/juju/ansiterm v1.0.0 h1:gmMvnZRq7JZJx6jkfSq9/+2LMrVEwGwt7UR6G+lmDEg= github.com/juju/ansiterm v1.0.0/go.mod h1:PyXUpnI3olx3bsPcHt98FGPX/KCFZ1Fi+hw1XLI6384= github.com/juju/blobstore/v2 v2.0.0 h1:pYXYE7m/RL73EfuwWMQZNuG60jXlL+OsI1qVOM86nwk= github.com/juju/blobstore/v2 v2.0.0/go.mod h1:lFTSngYRJBy/mUOWUjAghwKcP0iXxqBYqJtuchC3cJI= -github.com/juju/charm/v8 v8.0.1 h1:hV34C9nZx0+/PvBH4seAew3S5skZpEcn1vmL1TZ0DPg= -github.com/juju/charm/v8 v8.0.1/go.mod h1:tZ0JfWOdv11qu4Gm5lPD0KHBeuVUH2vbrKFyYS6JUAw= +github.com/juju/charm/v8 v8.0.2 h1:SZJ3rI4xndZJVCO/LyQ5XFr6RX6qWgUDiJEnk0kv4kA= +github.com/juju/charm/v8 v8.0.2/go.mod h1:tZ0JfWOdv11qu4Gm5lPD0KHBeuVUH2vbrKFyYS6JUAw= github.com/juju/charmrepo/v6 v6.0.2 h1:5murmFbdrItlF292k7z3H5pY5gheOxhMNZVfdhG0tG8= github.com/juju/charmrepo/v6 v6.0.2/go.mod h1:7CWTdKfp00iD9XqlgNpWm1HBBLe09/vGQHwYVPqXouY= github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=