forked from juju/juju
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Client Facade and CLI changes for export bundle
- Loading branch information
Showing
7 changed files
with
394 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
// Copyright 2018 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
// Package bundle provides access to the bundle api facade. | ||
// This facade contains api calls that are specific to bundles. | ||
|
||
package bundle | ||
|
||
import ( | ||
"github.com/juju/errors" | ||
"github.com/juju/loggo" | ||
|
||
"github.com/juju/juju/api/base" | ||
"github.com/juju/juju/apiserver/params" | ||
) | ||
|
||
var logger = loggo.GetLogger("juju.api.bundle") | ||
|
||
// Client allows access to the bundle API end point. | ||
type Client struct { | ||
base.ClientFacade | ||
st base.APICallCloser | ||
facade base.FacadeCaller | ||
} | ||
|
||
// NewClient creates a new client for accessing the bundle api. | ||
func NewClient(st base.APICallCloser) *Client { | ||
frontend, backend := base.NewClientFacade(st, "Bundle") | ||
return &Client{ | ||
ClientFacade: frontend, | ||
st: st, | ||
facade: backend} | ||
} | ||
|
||
// ExportBundle exports the current model configuration. | ||
func (c *Client) ExportBundle() (string, error) { | ||
var result params.StringResult | ||
if bestVer := c.BestAPIVersion(); bestVer < 2 { | ||
return "", errors.Errorf("command not supported on v%d", bestVer) | ||
} | ||
|
||
if err := c.facade.FacadeCall("ExportBundle", nil, &result); err != nil { | ||
return "", errors.Trace(err) | ||
} | ||
|
||
if len(result.Result) == 0 { | ||
return "", errors.Errorf("result obtained is incorrect") | ||
} | ||
return result.Result, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Copyright 2018 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package bundle_test | ||
|
||
import ( | ||
jc "github.com/juju/testing/checkers" | ||
gc "gopkg.in/check.v1" | ||
|
||
basetesting "github.com/juju/juju/api/base/testing" | ||
"github.com/juju/juju/api/bundle" | ||
"github.com/juju/juju/apiserver/params" | ||
coretesting "github.com/juju/juju/testing" | ||
) | ||
|
||
type bundleMockSuite struct { | ||
coretesting.BaseSuite | ||
bundleClient *bundle.Client | ||
} | ||
|
||
var _ = gc.Suite(&bundleMockSuite{}) | ||
|
||
func newClient(f basetesting.APICallerFunc, ver int) *bundle.Client { | ||
return bundle.NewClient(basetesting.BestVersionCaller{f, ver}) | ||
} | ||
|
||
func (s *bundleMockSuite) TestFailExportBundlev1(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 | ||
}, 1, | ||
) | ||
result, err := client.ExportBundle() | ||
c.Assert(err, gc.ErrorMatches, "command not supported on v1") | ||
c.Assert(result, jc.DeepEquals, "") | ||
} | ||
|
||
func (s *bundleMockSuite) TestExportBundlev2(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 = "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" | ||
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") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright 2018 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package bundle_test | ||
|
||
import ( | ||
"testing" | ||
|
||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
func TestAll(t *testing.T) { | ||
gc.TestingT(t) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright 2018 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
package model | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/juju/cmd" | ||
"github.com/juju/errors" | ||
"github.com/juju/gnuflag" | ||
|
||
"github.com/juju/juju/api/bundle" | ||
"github.com/juju/juju/cmd/modelcmd" | ||
"github.com/juju/juju/cmd/output" | ||
) | ||
|
||
// NewExportBundleCommand returns a fully constructed export bundle command. | ||
func NewExportBundleCommand() cmd.Command { | ||
return modelcmd.Wrap(&exportBundleCommand{}) | ||
} | ||
|
||
type exportBundleCommand struct { | ||
modelcmd.ModelCommandBase | ||
out cmd.Output | ||
api ExportBundleModelAPI | ||
// name of the charm bundle file. | ||
Filename string | ||
} | ||
|
||
const exportBundleHelpDoc = ` | ||
Exports the current model configuration into a YAML file. | ||
Examples: | ||
juju export-bundle | ||
If --filename is not used, the bundle is displayed in stdout. | ||
` | ||
|
||
// Info implements Command. | ||
func (c *exportBundleCommand) Info() *cmd.Info { | ||
return &cmd.Info{ | ||
Name: "export-bundle", | ||
Purpose: "Exports the current model configuration in a charm bundle.", | ||
Doc: exportBundleHelpDoc, | ||
} | ||
} | ||
|
||
// SetFlags implements Command. | ||
func (c *exportBundleCommand) SetFlags(f *gnuflag.FlagSet) { | ||
c.ModelCommandBase.SetFlags(f) | ||
c.out.AddFlags(f, "yaml", output.DefaultFormatters) | ||
f.StringVar(&c.Filename, "filename", "", "Export Model") | ||
} | ||
|
||
// Init implements Command. | ||
func (c *exportBundleCommand) Init(args []string) error { | ||
return cmd.CheckEmpty(args) | ||
} | ||
|
||
// ExportBundleAPI specifies the used function calls of the ModelManager. | ||
type ExportBundleModelAPI interface { | ||
Close() error | ||
BestAPIVersion() int | ||
ExportBundle() (string, error) | ||
} | ||
|
||
func (c *exportBundleCommand) getAPI() (ExportBundleModelAPI, error) { | ||
if c.api != nil { | ||
return c.api, nil | ||
} | ||
|
||
api, err := c.NewAPIRoot() | ||
if err != nil { | ||
return nil, errors.Trace(err) | ||
} | ||
return bundle.NewClient(api), nil | ||
} | ||
|
||
// Run implements Command. | ||
func (c *exportBundleCommand) Run(ctx *cmd.Context) error { | ||
client, err := c.getAPI() | ||
if err != nil { | ||
return err | ||
} | ||
defer client.Close() | ||
|
||
var result string | ||
if client.BestAPIVersion() > 1 { | ||
result, err = client.ExportBundle() | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
if c.Filename != "" { | ||
filename := c.Filename + ".yaml" | ||
file, err := os.Create(filename) | ||
if err != nil { | ||
return errors.Annotate(err, "while creating local file") | ||
} | ||
defer file.Close() | ||
|
||
// Write out the result. | ||
_, err = file.WriteString(result) | ||
if err != nil { | ||
return errors.Annotate(err, "while copying in local file") | ||
} | ||
|
||
// Print the local filename. | ||
fmt.Fprintln(ctx.Stdout, "Bundle successfully exported to", filename) | ||
} else { | ||
c.out.Write(ctx, result) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.