Skip to content

Commit

Permalink
Add option to export-bundle to inlude charm defaults
Browse files Browse the repository at this point in the history
  • Loading branch information
wallyworld committed May 18, 2021
1 parent b0eaef0 commit bc00f2f
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 67 deletions.
9 changes: 7 additions & 2 deletions api/bundle/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,18 @@ func (c *Client) GetChangesMapArgs(bundleURL, bundleDataYAML string) (params.Bun
}

// ExportBundle exports the current model configuration.
func (c *Client) ExportBundle() (string, error) {
func (c *Client) ExportBundle(includeDefaults bool) (string, error) {
var result params.StringResult
if bestVer := c.BestAPIVersion(); bestVer < 2 {
return "", errors.Errorf("this controller version does not support bundle export feature.")
} else if bestVer < 5 && includeDefaults {
return "", errors.Errorf("this controller version does not support bundle export with charm defaults.")
}

if err := c.facade.FacadeCall("ExportBundle", nil, &result); err != nil {
arg := params.ExportBundleParams{
IncludeCharmDefaults: includeDefaults,
}
if err := c.facade.FacadeCall("ExportBundle", arg, &result); err != nil {
return "", errors.Trace(err)
}

Expand Down
39 changes: 33 additions & 6 deletions api/bundle/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,37 @@ func (s *bundleMockSuite) TestFailExportBundlev1(c *gc.C) {
return nil
}, 1,
)
result, err := client.ExportBundle()
result, err := client.ExportBundle(false)
c.Assert(err, gc.NotNil)
c.Assert(err.Error(), gc.Equals, "this controller version does not support bundle export feature.")
c.Assert(result, jc.DeepEquals, "")
}

func (s *bundleMockSuite) TestExportBundlev2(c *gc.C) {
func (s *bundleMockSuite) TestFailExportBundleWithDefaults(c *gc.C) {
client := newClient(
func(objType string,
version int,
id,
request string,
args,
response interface{},
) error {
c.Check(objType, gc.Equals, "Bundle")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "ExportBundle")
c.Assert(args, gc.Equals, nil)
result := response.(*params.StringResult)
result.Result = ""
return nil
}, 4,
)
result, err := client.ExportBundle(true)
c.Assert(err, gc.NotNil)
c.Assert(err.Error(), gc.Equals, "this controller version does not support bundle export with charm defaults.")
c.Assert(result, jc.DeepEquals, "")
}

func (s *bundleMockSuite) TestExportBundleLatest(c *gc.C) {
bundle := `applications:
ubuntu:
charm: cs:trusty/ubuntu
Expand All @@ -312,12 +336,15 @@ func (s *bundleMockSuite) TestExportBundlev2(c *gc.C) {
args,
response interface{},
) error {
c.Assert(args, jc.DeepEquals, params.ExportBundleParams{
IncludeCharmDefaults: true,
})
result := response.(*params.StringResult)
result.Result = bundle
return nil
}, 2,
}, 5,
)
result, err := client.ExportBundle()
result, err := client.ExportBundle(true)
c.Assert(err, jc.ErrorIsNil)
c.Assert(result, jc.DeepEquals, bundle)
}
Expand All @@ -337,7 +364,7 @@ func (s *bundleMockSuite) TestExportBundleNotNilParamsErrorv2(c *gc.C) {
return result.Error
}, 2,
)
result, err := client.ExportBundle()
result, err := client.ExportBundle(false)
c.Assert(err, gc.NotNil)
c.Assert(result, jc.DeepEquals, "")
c.Check(err.Error(), gc.Matches, "export failed nothing to export as there are no applications")
Expand All @@ -356,7 +383,7 @@ func (s *bundleMockSuite) TestExportBundleFailNoParamsErrorv2(c *gc.C) {
return errors.New("foo")
}, 2,
)
result, err := client.ExportBundle()
result, err := client.ExportBundle(false)
c.Assert(err, gc.NotNil)
c.Assert(result, jc.DeepEquals, "")
c.Check(err.Error(), gc.Matches, "foo")
Expand Down
2 changes: 1 addition & 1 deletion api/facadeversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var facadeVersions = map[string]int{
"ApplicationScaler": 1,
"Backups": 2,
"Block": 2,
"Bundle": 4,
"Bundle": 5,
"CAASAgent": 1,
"CAASAdmission": 1,
"CAASApplication": 1,
Expand Down
1 change: 1 addition & 0 deletions apiserver/allfacades.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ func AllFacades() *facade.Registry {
reg("Bundle", 2, bundle.NewFacadeV2)
reg("Bundle", 3, bundle.NewFacadeV3)
reg("Bundle", 4, bundle.NewFacadeV4)
reg("Bundle", 5, bundle.NewFacadeV5)
reg("CharmHub", 1, charmhub.NewFacade)
reg("CharmRevisionUpdater", 2, charmrevisionupdater.NewCharmRevisionUpdaterAPI)
reg("Charms", 2, charms.NewFacadeV2)
Expand Down
67 changes: 56 additions & 11 deletions apiserver/facades/client/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,20 +42,27 @@ type APIv1 struct {

// APIv2 provides the Bundle API facade for version 2.
type APIv2 struct {
*BundleAPI
*APIv3
}

// APIv3 provides the Bundle API facade for version 3. It is otherwise
// identical to V2 with the exception that the V3 ExportBundle implementation
// also exposes the the current trust status for each application.
type APIv3 struct {
*BundleAPI
*APIv4
}

// APIv4 provides the Bundle API facade for version 4. It is otherwise
// identical to V3 with the exception that the V4 now has GetChangesAsMap, which
// returns the same data as GetChanges, but with better args data.
type APIv4 struct {
*APIv5
}

// APIv5 provides the Bundle API facade for version 5. It is otherwise
// identical to V4 with the exception that the V5 adds an arg to export
// bundle to control what is exported..
type APIv5 struct {
*BundleAPI
}

Expand All @@ -81,7 +88,7 @@ func NewFacadeV1(ctx facade.Context) (*APIv1, error) {
// NewFacadeV2 provides the signature required for facade registration
// for version 2.
func NewFacadeV2(ctx facade.Context) (*APIv2, error) {
api, err := newFacade(ctx)
api, err := NewFacadeV3(ctx)
if err != nil {
return nil, errors.Trace(err)
}
Expand All @@ -91,7 +98,7 @@ func NewFacadeV2(ctx facade.Context) (*APIv2, error) {
// NewFacadeV3 provides the signature required for facade registration
// for version 3.
func NewFacadeV3(ctx facade.Context) (*APIv3, error) {
api, err := newFacade(ctx)
api, err := NewFacadeV4(ctx)
if err != nil {
return nil, errors.Trace(err)
}
Expand All @@ -101,13 +108,23 @@ func NewFacadeV3(ctx facade.Context) (*APIv3, error) {
// NewFacadeV4 provides the signature required for facade registration
// for version 4.
func NewFacadeV4(ctx facade.Context) (*APIv4, error) {
api, err := newFacade(ctx)
api, err := NewFacadeV5(ctx)
if err != nil {
return nil, errors.Trace(err)
}
return &APIv4{api}, nil
}

// NewFacadeV5 provides the signature required for facade registration
// for version 5.
func NewFacadeV5(ctx facade.Context) (*APIv5, error) {
api, err := newFacade(ctx)
if err != nil {
return nil, errors.Trace(err)
}
return &APIv5{api}, nil
}

// NewFacade provides the required signature for facade registration.
func newFacade(ctx facade.Context) (*BundleAPI, error) {
authorizer := ctx.Auth()
Expand Down Expand Up @@ -138,6 +155,8 @@ func NewBundleAPI(
}

// NewBundleAPIv1 returns the new Bundle APIv1 facade.
// Deprecated:this only exists to support the deprecated
// client.GetBundleChanges() API.
func NewBundleAPIv1(
st Backend,
auth facade.Authorizer,
Expand All @@ -147,7 +166,7 @@ func NewBundleAPIv1(
if err != nil {
return nil, errors.Trace(err)
}
return &APIv1{&APIv2{api}}, nil
return &APIv1{&APIv2{&APIv3{&APIv4{&APIv5{api}}}}}, nil
}

func (b *BundleAPI) checkCanRead() error {
Expand Down Expand Up @@ -353,8 +372,13 @@ func getChangesMapArgs(
return results, err
}

// ExportBundle v4 did not have any parameters.
func (b *APIv4) ExportBundle() (params.StringResult, error) {
return b.APIv5.ExportBundle(params.ExportBundleParams{})
}

// ExportBundle exports the current model configuration as bundle.
func (b *BundleAPI) ExportBundle() (params.StringResult, error) {
func (b *BundleAPI) ExportBundle(arg params.ExportBundleParams) (params.StringResult, error) {
fail := func(failErr error) (params.StringResult, error) {
return params.StringResult{}, apiservererrors.ServerError(failErr)
}
Expand All @@ -370,7 +394,7 @@ func (b *BundleAPI) ExportBundle() (params.StringResult, error) {
}

// Fill it in charm.BundleData data structure.
bundleData, err := b.fillBundleData(model)
bundleData, err := b.fillBundleData(model, arg.IncludeCharmDefaults, b.backend)
if err != nil {
return fail(err)
}
Expand Down Expand Up @@ -449,7 +473,7 @@ func bundleOutputFromBundleData(bd *charm.BundleData) *bundleOutput {
// Mask the new method from V1 API.
func (u *APIv1) ExportBundle() (_, _ struct{}) { return }

func (b *BundleAPI) fillBundleData(model description.Model) (*charm.BundleData, error) {
func (b *BundleAPI) fillBundleData(model description.Model, includeCharmDefaults bool, backend Backend) (*charm.BundleData, error) {
cfg := model.Config()
value, ok := cfg["default-series"]
if !ok {
Expand Down Expand Up @@ -483,6 +507,7 @@ func (b *BundleAPI) fillBundleData(model description.Model) (*charm.BundleData,
printEndpointBindingSpaceNames := b.printSpaceNamesInEndpointBindings(model.Applications())
machineIds := set.NewStrings()
usedSeries := set.NewStrings()
charmConfigCache := make(map[string]*charm.Config)
for _, application := range model.Applications() {
var newApplication *charm.ApplicationSpec
appSeries := application.Series()
Expand Down Expand Up @@ -526,13 +551,33 @@ func (b *BundleAPI) fillBundleData(model description.Model) (*charm.BundleData,
channel = application.Channel()
}

charmCfg := application.CharmConfig()
if includeCharmDefaults {
// Augment the user specified config with defaults
// from the charm config metadata.
cfgInfo, ok := charmConfigCache[charmURL]
if !ok {
ch, err := backend.Charm(curl)
if err != nil {
return nil, errors.Trace(err)
}
cfgInfo = ch.Config()
charmConfigCache[charmURL] = cfgInfo
}
for name, opt := range cfgInfo.Options {
if _, ok := charmCfg[name]; ok {
continue
}
charmCfg[name] = opt.Default
}
}
if application.Subordinate() {
newApplication = &charm.ApplicationSpec{
Charm: charmURL,
Channel: channel,
Expose: exposedFlag,
ExposedEndpoints: exposedEndpoints,
Options: application.CharmConfig(),
Options: charmCfg,
Annotations: application.Annotations(),
EndpointBindings: endpointsWithSpaceNames,
}
Expand Down Expand Up @@ -571,7 +616,7 @@ func (b *BundleAPI) fillBundleData(model description.Model) (*charm.BundleData,
To: ut,
Expose: exposedFlag,
ExposedEndpoints: exposedEndpoints,
Options: application.CharmConfig(),
Options: charmCfg,
Annotations: application.Annotations(),
EndpointBindings: endpointsWithSpaceNames,
}
Expand Down
Loading

0 comments on commit bc00f2f

Please sign in to comment.