github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/firewall/setrule.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package firewall
     5  
     6  import (
     7  	"fmt"
     8  	"net"
     9  	"strings"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/gnuflag"
    14  
    15  	"github.com/juju/juju/api/firewallrules"
    16  	"github.com/juju/juju/apiserver/params"
    17  	jujucmd "github.com/juju/juju/cmd"
    18  	"github.com/juju/juju/cmd/juju/block"
    19  	"github.com/juju/juju/cmd/modelcmd"
    20  )
    21  
    22  var setRuleHelpSummary = `
    23  Sets a firewall rule.`[1:]
    24  
    25  var setRuleHelpDetails = `
    26  Firewall rules control ingress to a well known services
    27  within a Juju model. A rule consists of the service name
    28  and a whitelist of allowed ingress subnets.
    29  The currently supported services are:
    30  %v
    31  
    32  Examples:
    33      juju set-firewall-rule ssh --whitelist 192.168.1.0/16
    34      juju set-firewall-rule juju-controller --whitelist 192.168.1.0/16
    35      juju set-firewall-rule juju-application-offer --whitelist 192.168.1.0/16
    36  
    37  See also: 
    38      list-firewall-rules`
    39  
    40  // NewSetFirewallRuleCommand returns a command to set firewall rules.
    41  func NewSetFirewallRuleCommand() cmd.Command {
    42  	cmd := &setFirewallRuleCommand{}
    43  	cmd.newAPIFunc = func() (SetFirewallRuleAPI, error) {
    44  		root, err := cmd.NewAPIRoot()
    45  		if err != nil {
    46  			return nil, errors.Trace(err)
    47  		}
    48  		return firewallrules.NewClient(root), nil
    49  
    50  	}
    51  	return modelcmd.Wrap(cmd)
    52  }
    53  
    54  type setFirewallRuleCommand struct {
    55  	modelcmd.ModelCommandBase
    56  	modelcmd.IAASOnlyCommand
    57  	service        string
    58  	whitelistValue string
    59  
    60  	whiteList  []string
    61  	newAPIFunc func() (SetFirewallRuleAPI, error)
    62  }
    63  
    64  // Info implements cmd.Command.
    65  func (c *setFirewallRuleCommand) Info() *cmd.Info {
    66  	supportedRules := []string{
    67  		" -" + string(params.SSHRule),
    68  		" -" + string(params.JujuControllerRule),
    69  		" -" + string(params.JujuApplicationOfferRule),
    70  	}
    71  	return jujucmd.Info(&cmd.Info{
    72  		Name:    "set-firewall-rule",
    73  		Args:    "<service-name>, --whitelist <cidr>[,<cidr>...]",
    74  		Purpose: setRuleHelpSummary,
    75  		Doc:     fmt.Sprintf(setRuleHelpDetails, strings.Join(supportedRules, "\n")),
    76  	})
    77  }
    78  
    79  // SetFlags implements cmd.Command.
    80  func (c *setFirewallRuleCommand) SetFlags(f *gnuflag.FlagSet) {
    81  	f.StringVar(&c.whitelistValue, "whitelist", "", "list of subnets to whitelist")
    82  }
    83  
    84  // Init implements cmd.Command.
    85  func (c *setFirewallRuleCommand) Init(args []string) (err error) {
    86  	if len(args) == 1 {
    87  		c.service = args[0]
    88  		if c.whitelistValue == "" {
    89  			return errors.New("no whitelist subnets specified")
    90  		}
    91  		if err := c.parseCIDRs(&c.whiteList, c.whitelistValue); err != nil {
    92  			return errors.Annotate(err, "invalid white-list subnet")
    93  		}
    94  		return nil
    95  	}
    96  	if len(args) == 0 {
    97  		return errors.New("no well known service specified")
    98  	}
    99  	return cmd.CheckEmpty(args[1:])
   100  }
   101  
   102  func (c *setFirewallRuleCommand) parseCIDRs(cidrs *[]string, value string) error {
   103  	if value == "" {
   104  		return nil
   105  	}
   106  	rawValues := strings.Split(value, ",")
   107  	for _, cidrStr := range rawValues {
   108  		cidrStr = strings.TrimSpace(cidrStr)
   109  		if _, _, err := net.ParseCIDR(cidrStr); err != nil {
   110  			return err
   111  		}
   112  		*cidrs = append(*cidrs, cidrStr)
   113  	}
   114  	return nil
   115  }
   116  
   117  // SetFirewallRuleAPI defines the API methods that the set firewall rules command uses.
   118  type SetFirewallRuleAPI interface {
   119  	Close() error
   120  	SetFirewallRule(service string, whiteListCidrs []string) error
   121  }
   122  
   123  func (c *setFirewallRuleCommand) Run(_ *cmd.Context) error {
   124  	client, err := c.newAPIFunc()
   125  	if err != nil {
   126  		return err
   127  	}
   128  	defer client.Close()
   129  	err = client.SetFirewallRule(c.service, c.whiteList)
   130  	return block.ProcessBlockedError(err, block.BlockChange)
   131  }