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 }