Skip to content

Commit

Permalink
Expose GetChangesMapArgs for clients to use
Browse files Browse the repository at this point in the history
The following exposes GetChangesMapArgs on the Bundle api server,
including adding the methods to the Bundle client. The changes in
the cmd/.../bundle.go requires a LOT of changes, which requires
more time than I've currently got. So instead of doing it in one
stage, I've updated it to make it better than before and left a
very large TODO. Either I'll get time to finish it off at some
point, or someone else will...

In an ideal world, most of the overlay bundle changes would also
be put on the server, again this is a multi-day effort to get it
working and tested, so that again is left as an exercise of the
reader.

What do work at the moment is getting a map of arguments from the
api server, so clients like pylib can work without jumping through
hoops and crashing everytime someone updates bundlechanges.

Note: bundlechanges is a minefield to clients :o
  • Loading branch information
SimonRichardson committed Sep 4, 2019
1 parent de23e65 commit de69720
Show file tree
Hide file tree
Showing 8 changed files with 707 additions and 39 deletions.
4 changes: 2 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Gopkg.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
name = "github.com/hashicorp/raft-boltdb"

[[constraint]]
revision = "2ab5b6004f111b9f4792a67b14e2f03c37e0af1d"
revision = "3ef4201dfd2495d7a56be07a4d095fa624167067"
name = "github.com/juju/bundlechanges"

[[constraint]]
Expand Down
31 changes: 31 additions & 0 deletions api/bundle/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,37 @@ func NewClient(st base.APICallCloser) *Client {
facade: backend}
}

// GetChanges returns back the changes for a given bundle that need to be
// applied.
// GetChanges is superseded by GetChangesMapArgs, use that where possible, by
// detecting the BestAPIVersion to use.
func (c *Client) GetChanges(bundleURL, bundleDataYAML string) (params.BundleChangesResults, error) {
var result params.BundleChangesResults
if err := c.facade.FacadeCall("GetChanges", params.BundleChangesParams{
BundleURL: bundleURL,
BundleDataYAML: bundleDataYAML,
}, &result); err != nil {
return result, errors.Trace(err)
}
return result, nil
}

// GetChangesMapArgs returns back the changes for a given bundle that need to be
// applied, with the args of a method as a map.
func (c *Client) GetChangesMapArgs(bundleURL, bundleDataYAML string) (params.BundleChangesMapArgsResults, error) {
var result params.BundleChangesMapArgsResults
if bestVer := c.BestAPIVersion(); bestVer < 4 {
return result, errors.Errorf("this controller version does not support bundle get changes as map args feature.")
}
if err := c.facade.FacadeCall("GetChangesMapArgs", params.BundleChangesParams{
BundleURL: bundleURL,
BundleDataYAML: bundleDataYAML,
}, &result); err != nil {
return result, errors.Trace(err)
}
return result, nil
}

// ExportBundle exports the current model configuration.
func (c *Client) ExportBundle() (string, error) {
var result params.StringResult
Expand Down
280 changes: 256 additions & 24 deletions api/bundle/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,248 @@ func newClient(f basetesting.APICallerFunc, ver int) *bundle.Client {
return bundle.NewClient(basetesting.BestVersionCaller{f, ver})
}

func (s *bundleMockSuite) TestGetChanges(c *gc.C) {
bundleURL := "cs:bundle-url"
bundleYAML := `applications:
ubuntu:
charm: cs:trusty/ubuntu
series: trusty
num_units: 1
options:
key: value
series: xenial
relations:
- []`
changes := []*params.BundleChange{
{
Id: "addCharm-0",
Method: "addCharm",
Args: []interface{}{"cs:trusty/ubuntu", "trusty", ""},
Requires: []string{},
},
{
Id: "deploy-1",
Method: "deploy",
Args: []interface{}{
"$addCharm-0",
"trusty",
"ubuntu",
map[string]interface{}{
"key": "value",
"series": "xenial",
},
"",
map[string]string{},
map[string]string{},
map[string]int{},
1,
},
Requires: []string{"$addCharm-0"},
},
}
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, "GetChanges")
c.Assert(args, gc.Equals, params.BundleChangesParams{
BundleDataYAML: bundleYAML,
BundleURL: bundleURL,
})
result := response.(*params.BundleChangesResults)
result.Changes = changes
return nil
}, 2,
)
result, err := client.GetChanges(bundleURL, bundleYAML)
c.Assert(err, jc.ErrorIsNil)
c.Assert(result.Errors, gc.DeepEquals, []string(nil))
c.Assert(result.Changes, gc.DeepEquals, changes)
}

func (s *bundleMockSuite) TestGetChangesReturnsErrors(c *gc.C) {
bundleURL := "cs:bundle-url"
bundleYAML := `applications:
ubuntu:
charm: cs:trusty/ubuntu
series: trusty
num_units: 1
options:
key: value
series: xenial`
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, "GetChanges")
c.Assert(args, gc.Equals, params.BundleChangesParams{
BundleDataYAML: bundleYAML,
BundleURL: bundleURL,
})
result := response.(*params.BundleChangesResults)
result.Errors = []string{
"Error returned from request",
}
return nil
}, 2,
)
result, err := client.GetChanges(bundleURL, bundleYAML)
c.Assert(err, jc.ErrorIsNil)
c.Assert(result.Errors, gc.DeepEquals, []string{"Error returned from request"})
c.Assert(result.Changes, gc.DeepEquals, []*params.BundleChange(nil))
}

func (s *bundleMockSuite) TestGetChangesMapArgs(c *gc.C) {
bundleURL := "cs:bundle-url"
bundleYAML := `applications:
ubuntu:
charm: cs:trusty/ubuntu
series: trusty
num_units: 1
options:
key: value
series: xenial`
changes := []*params.BundleChangesMapArgs{
{
Id: "addCharm-0",
Method: "addCharm",
Args: map[string]interface{}{
"charm": "cs:trusty/ubuntu",
"series": "trusty",
},
Requires: []string{},
},
{
Id: "deploy-1",
Method: "deploy",
Args: map[string]interface{}{
"charm": "$addCharm-0",
"series": "trusty",
"num_units": "1",
"options": map[string]interface{}{
"key": "value",
"series": "xenial",
},
},
Requires: []string{"$addCharm-0"},
},
}
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, "GetChangesMapArgs")
c.Assert(args, gc.Equals, params.BundleChangesParams{
BundleDataYAML: bundleYAML,
BundleURL: bundleURL,
})
result := response.(*params.BundleChangesMapArgsResults)
result.Changes = changes
return nil
}, 4,
)
result, err := client.GetChangesMapArgs(bundleURL, bundleYAML)
c.Assert(err, jc.ErrorIsNil)
c.Assert(result.Errors, gc.DeepEquals, []string(nil))
c.Assert(result.Changes, gc.DeepEquals, changes)
}

func (s *bundleMockSuite) TestGetChangesMapArgsReturnsErrors(c *gc.C) {
bundleURL := "cs:bundle-url"
bundleYAML := `applications:
ubuntu:
charm: cs:trusty/ubuntu
series: trusty
num_units: 1
options:
key: value
series: xenial
relations:
- []`
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, "GetChangesMapArgs")
c.Assert(args, gc.Equals, params.BundleChangesParams{
BundleDataYAML: bundleYAML,
BundleURL: bundleURL,
})
result := response.(*params.BundleChangesMapArgsResults)
result.Errors = []string{
"Error returned from request",
}
return nil
}, 4,
)
result, err := client.GetChangesMapArgs(bundleURL, bundleYAML)
c.Assert(err, jc.ErrorIsNil)
c.Assert(result.Errors, gc.DeepEquals, []string{"Error returned from request"})
c.Assert(result.Changes, gc.DeepEquals, []*params.BundleChangesMapArgs(nil))
}

func (s *bundleMockSuite) TestGetChangesMapArgsV3(c *gc.C) {
bundleURL := "cs:bundle-url"
bundleYAML := `applications:
ubuntu:
charm: cs:trusty/ubuntu
series: trusty
num_units: 1
options:
key: value
series: xenial
relations:
- []`
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, "GetChangesMapArgs")
c.Assert(args, gc.Equals, params.BundleChangesParams{
BundleDataYAML: bundleYAML,
BundleURL: bundleURL,
})
result := response.(*params.BundleChangesMapArgsResults)
result.Errors = []string{
"Error returned from request",
}
return nil
}, 3,
)
_, err := client.GetChangesMapArgs(bundleURL, bundleYAML)
c.Assert(err, gc.ErrorMatches, "this controller version does not support bundle get changes as map args feature.")
}

func (s *bundleMockSuite) TestFailExportBundlev1(c *gc.C) {
client := newClient(
func(objType string,
Expand All @@ -51,6 +293,18 @@ func (s *bundleMockSuite) TestFailExportBundlev1(c *gc.C) {
}

func (s *bundleMockSuite) TestExportBundlev2(c *gc.C) {
bundle := `applications:
ubuntu:
charm: cs:trusty/ubuntu
series: trusty
num_units: 1
to:
- \"0\"
options:
key: value
series: xenial
relations:
- []`
client := newClient(
func(objType string, version int,
id,
Expand All @@ -59,35 +313,13 @@ func (s *bundleMockSuite) TestExportBundlev2(c *gc.C) {
response interface{},
) error {
result := response.(*params.StringResult)
result.Result = "applications:\n " +
"ubuntu:\n " +
"charm: cs:trusty/ubuntu\n " +
"series: trusty\n " +
"num_units: 1\n " +
"to:\n " +
"- \"0\"\n " +
"options:\n " +
"key: value\n" +
"series: xenial\n" +
"relations:\n" +
"- []\n"
result.Result = bundle
return nil
}, 2,
)
result, err := client.ExportBundle()
c.Assert(err, jc.ErrorIsNil)
c.Assert(result, jc.DeepEquals, "applications:\n "+
"ubuntu:\n "+
"charm: cs:trusty/ubuntu\n "+
"series: trusty\n "+
"num_units: 1\n "+
"to:\n "+
"- \"0\"\n "+
"options:\n "+
"key: value\n"+
"series: xenial\n"+
"relations:\n"+
"- []\n")
c.Assert(result, jc.DeepEquals, bundle)
}

func (s *bundleMockSuite) TestExportBundleNotNilParamsErrorv2(c *gc.C) {
Expand Down
Loading

0 comments on commit de69720

Please sign in to comment.