github.com/rogpeppe/juju@v0.0.0-20140613142852-6337964b789e/provider/joyent/environ_firewall.go (about)

     1  // Copyright 2013 Joyent Inc.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package joyent
     5  
     6  import (
     7  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/joyent/gosdc/cloudapi"
    12  
    13  	"github.com/juju/juju/environs/config"
    14  	"github.com/juju/juju/network"
    15  )
    16  
    17  const (
    18  	firewallRuleAll = "FROM tag %s TO tag juju ALLOW %s PORT %d"
    19  )
    20  
    21  // Helper method to create a firewall rule string for the given port
    22  func createFirewallRuleAll(env *joyentEnviron, port network.Port) string {
    23  	return fmt.Sprintf(firewallRuleAll, env.Name(), strings.ToLower(port.Protocol), port.Number)
    24  }
    25  
    26  // Helper method to check if a firewall rule string already exist
    27  func ruleExists(rules []cloudapi.FirewallRule, rule string) (bool, string) {
    28  	for _, r := range rules {
    29  		if strings.EqualFold(r.Rule, rule) {
    30  			return true, r.Id
    31  		}
    32  	}
    33  
    34  	return false, ""
    35  }
    36  
    37  // Helper method to get port from the given firewall rules
    38  func getPorts(env *joyentEnviron, rules []cloudapi.FirewallRule) []network.Port {
    39  	ports := []network.Port{}
    40  	for _, r := range rules {
    41  		rule := r.Rule
    42  		if r.Enabled && strings.HasPrefix(rule, "FROM tag "+env.Name()) && strings.Contains(rule, "PORT") {
    43  			p := rule[strings.Index(rule, "ALLOW")+6 : strings.Index(rule, "PORT")-1]
    44  			n, _ := strconv.Atoi(rule[strings.LastIndex(rule, " ")+1:])
    45  			port := network.Port{Protocol: p, Number: n}
    46  			ports = append(ports, port)
    47  		}
    48  	}
    49  
    50  	network.SortPorts(ports)
    51  	return ports
    52  }
    53  
    54  func (env *joyentEnviron) OpenPorts(ports []network.Port) error {
    55  	if env.Config().FirewallMode() != config.FwGlobal {
    56  		return fmt.Errorf("invalid firewall mode %q for opening ports on environment", env.Config().FirewallMode())
    57  	}
    58  
    59  	fwRules, err := env.compute.cloudapi.ListFirewallRules()
    60  	if err != nil {
    61  		return fmt.Errorf("cannot get firewall rules: %v", err)
    62  	}
    63  
    64  	for _, p := range ports {
    65  		rule := createFirewallRuleAll(env, p)
    66  		if e, id := ruleExists(fwRules, rule); e {
    67  			_, err := env.compute.cloudapi.EnableFirewallRule(id)
    68  			if err != nil {
    69  				return fmt.Errorf("couldn't enable rule %s: %v", rule, err)
    70  			}
    71  		} else {
    72  			_, err := env.compute.cloudapi.CreateFirewallRule(cloudapi.CreateFwRuleOpts{
    73  				Enabled: true,
    74  				Rule:    rule,
    75  			})
    76  			if err != nil {
    77  				return fmt.Errorf("couldn't create rule %s: %v", rule, err)
    78  			}
    79  		}
    80  	}
    81  
    82  	logger.Infof("ports %v opened in environment", ports)
    83  
    84  	return nil
    85  }
    86  
    87  func (env *joyentEnviron) ClosePorts(ports []network.Port) error {
    88  	if env.Config().FirewallMode() != config.FwGlobal {
    89  		return fmt.Errorf("invalid firewall mode %q for closing ports on environment", env.Config().FirewallMode())
    90  	}
    91  
    92  	fwRules, err := env.compute.cloudapi.ListFirewallRules()
    93  	if err != nil {
    94  		return fmt.Errorf("cannot get firewall rules: %v", err)
    95  	}
    96  
    97  	for _, p := range ports {
    98  		rule := createFirewallRuleAll(env, p)
    99  		if e, id := ruleExists(fwRules, rule); e {
   100  			_, err := env.compute.cloudapi.DisableFirewallRule(id)
   101  			if err != nil {
   102  				return fmt.Errorf("couldn't disable rule %s: %v", rule, err)
   103  			}
   104  		} else {
   105  			_, err := env.compute.cloudapi.CreateFirewallRule(cloudapi.CreateFwRuleOpts{
   106  				Enabled: false,
   107  				Rule:    rule,
   108  			})
   109  			if err != nil {
   110  				return fmt.Errorf("couldn't create rule %s: %v", rule, err)
   111  			}
   112  		}
   113  	}
   114  
   115  	logger.Infof("ports %v closed in environment", ports)
   116  
   117  	return nil
   118  }
   119  
   120  func (env *joyentEnviron) Ports() ([]network.Port, error) {
   121  	if env.Config().FirewallMode() != config.FwGlobal {
   122  		return nil, fmt.Errorf("invalid firewall mode %q for retrieving ports from environment", env.Config().FirewallMode())
   123  	}
   124  
   125  	fwRules, err := env.compute.cloudapi.ListFirewallRules()
   126  	if err != nil {
   127  		return nil, fmt.Errorf("cannot get firewall rules: %v", err)
   128  	}
   129  
   130  	return getPorts(env, fwRules), nil
   131  }