github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/provider/gce/google/conn_network.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package google
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  
     9  	"github.com/juju/juju/network"
    10  )
    11  
    12  // Ports build a list of all open port ranges for a given firewall name
    13  // (within the Connection's project) and returns it. If the firewall
    14  // does not exist then the list will be empty and no error is returned.
    15  func (gce Connection) Ports(fwname string) ([]network.PortRange, error) {
    16  	firewall, err := gce.raw.GetFirewall(gce.projectID, fwname)
    17  	if errors.IsNotFound(err) {
    18  		return nil, nil
    19  	}
    20  	if err != nil {
    21  		return nil, errors.Annotate(err, "while getting ports from GCE")
    22  	}
    23  
    24  	var ports []network.PortRange
    25  	for _, allowed := range firewall.Allowed {
    26  		for _, portRangeStr := range allowed.Ports {
    27  			portRange, err := network.ParsePortRange(portRangeStr)
    28  			if err != nil {
    29  				return ports, errors.Annotate(err, "bad ports from GCE")
    30  			}
    31  			portRange.Protocol = allowed.IPProtocol
    32  			ports = append(ports, portRange)
    33  		}
    34  	}
    35  
    36  	return ports, nil
    37  }
    38  
    39  // OpenPorts sends a request to the GCE API to open the provided port
    40  // ranges on the named firewall. If the firewall does not exist yet it
    41  // is created, with the provided port ranges opened. Otherwise the
    42  // existing firewall is updated to add the provided port ranges to the
    43  // ports it already has open. The call blocks until the ports are
    44  // opened or the request fails.
    45  func (gce Connection) OpenPorts(fwname string, ports ...network.PortRange) error {
    46  	// TODO(ericsnow) Short-circuit if ports is empty.
    47  
    48  	// Compose the full set of open ports.
    49  	currentPorts, err := gce.Ports(fwname)
    50  	if err != nil {
    51  		return errors.Trace(err)
    52  	}
    53  	inputPortsSet := network.NewPortSet(ports...)
    54  	if inputPortsSet.IsEmpty() {
    55  		return nil
    56  	}
    57  	currentPortsSet := network.NewPortSet(currentPorts...)
    58  
    59  	// Send the request, depending on the current ports.
    60  	if currentPortsSet.IsEmpty() {
    61  		// Create a new firewall.
    62  		firewall := firewallSpec(fwname, inputPortsSet)
    63  		if err := gce.raw.AddFirewall(gce.projectID, firewall); err != nil {
    64  			return errors.Annotatef(err, "opening port(s) %+v", ports)
    65  		}
    66  		return nil
    67  	}
    68  
    69  	// Update an existing firewall.
    70  	newPortsSet := currentPortsSet.Union(inputPortsSet)
    71  	firewall := firewallSpec(fwname, newPortsSet)
    72  	if err := gce.raw.UpdateFirewall(gce.projectID, fwname, firewall); err != nil {
    73  		return errors.Annotatef(err, "opening port(s) %+v", ports)
    74  	}
    75  	return nil
    76  }
    77  
    78  // ClosePorts sends a request to the GCE API to close the provided port
    79  // ranges on the named firewall. If the firewall does not exist nothing
    80  // happens. If the firewall is left with no ports then it is removed.
    81  // Otherwise it will be left with just the open ports it has that do not
    82  // match the provided port ranges. The call blocks until the ports are
    83  // closed or the request fails.
    84  func (gce Connection) ClosePorts(fwname string, ports ...network.PortRange) error {
    85  	// Compose the full set of open ports.
    86  	currentPorts, err := gce.Ports(fwname)
    87  	if err != nil {
    88  		return errors.Trace(err)
    89  	}
    90  	inputPortsSet := network.NewPortSet(ports...)
    91  	if inputPortsSet.IsEmpty() {
    92  		return nil
    93  	}
    94  	currentPortsSet := network.NewPortSet(currentPorts...)
    95  	newPortsSet := currentPortsSet.Difference(inputPortsSet)
    96  
    97  	// Send the request, depending on the current ports.
    98  	if newPortsSet.IsEmpty() {
    99  		// Delete a firewall.
   100  		// TODO(ericsnow) Handle case where firewall does not exist.
   101  		if err := gce.raw.RemoveFirewall(gce.projectID, fwname); err != nil {
   102  			return errors.Annotatef(err, "closing port(s) %+v", ports)
   103  		}
   104  		return nil
   105  	}
   106  
   107  	// Update an existing firewall.
   108  	firewall := firewallSpec(fwname, newPortsSet)
   109  	if err := gce.raw.UpdateFirewall(gce.projectID, fwname, firewall); err != nil {
   110  		return errors.Annotatef(err, "closing port(s) %+v", ports)
   111  	}
   112  	return nil
   113  }