github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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/httprequest"
    13  	"github.com/juju/webbrowser"
    14  	"launchpad.net/gnuflag"
    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  	f.BoolVar(&c.showCreds, "show-credentials", false, "show admin credentials to use for logging into the Juju GUI")
    61  	f.BoolVar(&c.noBrowser, "no-browser", false, "do not try to open the web browser, just print the Juju GUI URL")
    62  }
    63  
    64  // Run implements the cmd.Command interface.
    65  func (c *guiCommand) Run(ctx *cmd.Context) error {
    66  	// Retrieve model details.
    67  	conn, err := c.NewAPIRoot()
    68  	if err != nil {
    69  		return errors.Annotate(err, "cannot establish API connection")
    70  	}
    71  	defer conn.Close()
    72  	details, err := c.ClientStore().ModelByName(c.ControllerName(), c.AccountName(), c.ModelName())
    73  	if err != nil {
    74  		return errors.Annotate(err, "cannot retrieve model details")
    75  	}
    76  	rawURL := fmt.Sprintf("https://%s/gui/%s/", conn.Addr(), details.ModelUUID)
    77  
    78  	// Check that the Juju GUI is available.
    79  	if err = c.checkAvailable(rawURL, conn); err != nil {
    80  		return errors.Trace(err)
    81  	}
    82  
    83  	// Open the Juju GUI in the browser.
    84  	if err = c.openBrowser(ctx, rawURL); err != nil {
    85  		return errors.Trace(err)
    86  	}
    87  
    88  	// Print login credentials if requested.
    89  	if err = c.showCredentials(ctx); err != nil {
    90  		return errors.Trace(err)
    91  	}
    92  	return nil
    93  }
    94  
    95  // checkAvailable ensures the Juju GUI is available on the controller at the
    96  // given URL.
    97  func (c *guiCommand) checkAvailable(rawURL string, conn api.Connection) error {
    98  	client, err := conn.HTTPClient()
    99  	if err != nil {
   100  		return errors.Annotate(err, "cannot retrieve HTTP client")
   101  	}
   102  	if err = clientGet(client, rawURL); err != nil {
   103  		return errors.Annotate(err, "Juju GUI is not available")
   104  	}
   105  	return nil
   106  }
   107  
   108  // openBrowser opens the Juju GUI at the given URL.
   109  func (c *guiCommand) openBrowser(ctx *cmd.Context, rawURL string) error {
   110  	u, err := url.Parse(rawURL)
   111  	if err != nil {
   112  		return errors.Annotate(err, "cannot parse Juju GUI URL")
   113  	}
   114  	if c.noBrowser {
   115  		ctx.Infof(u.String())
   116  		return nil
   117  	}
   118  	err = webbrowserOpen(u)
   119  	if err == nil {
   120  		ctx.Infof("Opening the Juju GUI in your browser.")
   121  		ctx.Infof("If it does not open, open this URL:\n%s", u)
   122  		return nil
   123  	}
   124  	if err == webbrowser.ErrNoBrowser {
   125  		ctx.Infof("Open this URL in your browser:\n%s", u)
   126  		return nil
   127  	}
   128  	return errors.Annotate(err, "cannot open web browser")
   129  }
   130  
   131  // showCredentials shows the admin username and password.
   132  func (c *guiCommand) showCredentials(ctx *cmd.Context) error {
   133  	if !c.showCreds {
   134  		return nil
   135  	}
   136  	// TODO(wallyworld) - what to do if we are using a macaroon.
   137  	if c.AccountName() == "" {
   138  		return errors.Errorf("no connection credentials available")
   139  	}
   140  	accountDetails, err := c.ClientStore().AccountByName(
   141  		c.ControllerName(), c.AccountName(),
   142  	)
   143  	if err != nil {
   144  		return errors.Annotate(err, "cannot retrieve credentials")
   145  	}
   146  	ctx.Infof("Username: %s\nPassword: %s", accountDetails.User, accountDetails.Password)
   147  	return nil
   148  }
   149  
   150  // clientGet is defined for testing purposes.
   151  var clientGet = func(client *httprequest.Client, rawURL string) error {
   152  	return client.Get(rawURL, nil)
   153  }
   154  
   155  // webbrowserOpen is defined for testing purposes.
   156  var webbrowserOpen = webbrowser.Open