github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/gui/gui.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package gui
     5  
     6  import (
     7  	"fmt"
     8  	"net/url"
     9  
    10  	"github.com/juju/cmd"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/gnuflag"
    13  	"github.com/juju/httprequest"
    14  	"github.com/juju/webbrowser"
    15  
    16  	"github.com/juju/juju/api"
    17  	"github.com/juju/juju/cmd/modelcmd"
    18  )
    19  
    20  // NewGUICommand creates and returns a new gui command.
    21  func NewGUICommand() cmd.Command {
    22  	return modelcmd.Wrap(&guiCommand{})
    23  }
    24  
    25  // guiCommand opens the Juju GUI in the default browser.
    26  type guiCommand struct {
    27  	modelcmd.ModelCommandBase
    28  
    29  	showCreds bool
    30  	noBrowser bool
    31  }
    32  
    33  const guiDoc = `
    34  Open the Juju GUI in the default browser:
    35  
    36  	juju gui
    37  
    38  Open the GUI and show admin credentials to use to log into it:
    39  
    40  	juju gui --show-credentials
    41  
    42  Do not open the browser, just output the GUI URL:
    43  
    44  	juju gui --no-browser
    45  
    46  An error is returned if the Juju GUI is not available in the controller.
    47  `
    48  
    49  // Info implements the cmd.Command interface.
    50  func (c *guiCommand) Info() *cmd.Info {
    51  	return &cmd.Info{
    52  		Name:    "gui",
    53  		Purpose: "Open the Juju GUI in the default browser.",
    54  		Doc:     guiDoc,
    55  	}
    56  }
    57  
    58  // SetFlags implements the cmd.Command interface.
    59  func (c *guiCommand) SetFlags(f *gnuflag.FlagSet) {
    60  	c.ModelCommandBase.SetFlags(f)
    61  	f.BoolVar(&c.showCreds, "show-credentials", false, "Show admin credentials to use for logging into the Juju GUI")
    62  	f.BoolVar(&c.noBrowser, "no-browser", false, "Do not try to open the web browser, just print the Juju GUI URL")
    63  }
    64  
    65  // Run implements the cmd.Command interface.
    66  func (c *guiCommand) Run(ctx *cmd.Context) error {
    67  	// Retrieve model details.
    68  	conn, err := c.NewAPIRoot()
    69  	if err != nil {
    70  		return errors.Annotate(err, "cannot establish API connection")
    71  	}
    72  	defer conn.Close()
    73  	details, err := c.ClientStore().ModelByName(c.ControllerName(), c.ModelName())
    74  	if err != nil {
    75  		return errors.Annotate(err, "cannot retrieve model details")
    76  	}
    77  	rawURL := fmt.Sprintf("https://%s/gui/%s/", conn.Addr(), details.ModelUUID)
    78  
    79  	// Check that the Juju GUI is available.
    80  	if err = c.checkAvailable(rawURL, conn); err != nil {
    81  		return errors.Trace(err)
    82  	}
    83  
    84  	// Open the Juju GUI in the browser.
    85  	if err = c.openBrowser(ctx, rawURL); err != nil {
    86  		return errors.Trace(err)
    87  	}
    88  
    89  	// Print login credentials if requested.
    90  	if err = c.showCredentials(ctx); err != nil {
    91  		return errors.Trace(err)
    92  	}
    93  	return nil
    94  }
    95  
    96  // checkAvailable ensures the Juju GUI is available on the controller at the
    97  // given URL.
    98  func (c *guiCommand) checkAvailable(rawURL string, conn api.Connection) error {
    99  	client, err := conn.HTTPClient()
   100  	if err != nil {
   101  		return errors.Annotate(err, "cannot retrieve HTTP client")
   102  	}
   103  	if err = clientGet(client, rawURL); err != nil {
   104  		return errors.Annotate(err, "Juju GUI is not available")
   105  	}
   106  	return nil
   107  }
   108  
   109  // openBrowser opens the Juju GUI at the given URL.
   110  func (c *guiCommand) openBrowser(ctx *cmd.Context, rawURL string) error {
   111  	u, err := url.Parse(rawURL)
   112  	if err != nil {
   113  		return errors.Annotate(err, "cannot parse Juju GUI URL")
   114  	}
   115  	if c.noBrowser {
   116  		ctx.Infof(u.String())
   117  		return nil
   118  	}
   119  	err = webbrowserOpen(u)
   120  	if err == nil {
   121  		ctx.Infof("Opening the Juju GUI in your browser.")
   122  		ctx.Infof("If it does not open, open this URL:\n%s", u)
   123  		return nil
   124  	}
   125  	if err == webbrowser.ErrNoBrowser {
   126  		ctx.Infof("Open this URL in your browser:\n%s", u)
   127  		return nil
   128  	}
   129  	return errors.Annotate(err, "cannot open web browser")
   130  }
   131  
   132  // showCredentials shows the admin username and password.
   133  func (c *guiCommand) showCredentials(ctx *cmd.Context) error {
   134  	if !c.showCreds {
   135  		return nil
   136  	}
   137  	// TODO(wallyworld) - what to do if we are using a macaroon.
   138  	accountDetails, err := c.ClientStore().AccountDetails(c.ControllerName())
   139  	if err != nil {
   140  		return errors.Annotate(err, "cannot retrieve credentials")
   141  	}
   142  	ctx.Infof("Username: %s\nPassword: %s", accountDetails.User, accountDetails.Password)
   143  	return nil
   144  }
   145  
   146  // clientGet is defined for testing purposes.
   147  var clientGet = func(client *httprequest.Client, rawURL string) error {
   148  	return client.Get(rawURL, nil)
   149  }
   150  
   151  // webbrowserOpen is defined for testing purposes.
   152  var webbrowserOpen = webbrowser.Open