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 }