// flushGlobalPorts opens and closes global ports in the environment. // It keeps a reference count for ports so that only 0-to-1 and 1-to-0 events // modify the environment. func (fw *Firewaller) flushGlobalPorts(rawOpen, rawClose []network.Port) error { // Filter which ports are really to open or close. var toOpen, toClose []network.Port for _, port := range rawOpen { if fw.globalPortRef[port] == 0 { toOpen = append(toOpen, port) } fw.globalPortRef[port]++ } for _, port := range rawClose { fw.globalPortRef[port]-- if fw.globalPortRef[port] == 0 { toClose = append(toClose, port) delete(fw.globalPortRef, port) } } // Open and close the ports. if len(toOpen) > 0 { if err := fw.environ.OpenPorts(network.PortsToPortRanges(toOpen)); err != nil { // TODO(mue) Add local retry logic. return err } network.SortPorts(toOpen) logger.Infof("opened ports %v in environment", toOpen) } if len(toClose) > 0 { if err := fw.environ.ClosePorts(network.PortsToPortRanges(toClose)); err != nil { // TODO(mue) Add local retry logic. return err } network.SortPorts(toClose) logger.Infof("closed ports %v in environment", toClose) } return nil }
// reconcileInstances compares the initially started watcher for machines, // units and services with the opened and closed ports of the instances and // opens and closes the appropriate ports for each instance. func (fw *Firewaller) reconcileInstances() error { for _, machined := range fw.machineds { m, err := machined.machine() if params.IsCodeNotFound(err) { if err := fw.forgetMachine(machined); err != nil { return err } continue } else if err != nil { return err } instanceId, err := m.InstanceId() if err != nil { return err } instances, err := fw.environ.Instances([]instance.Id{instanceId}) if err == environs.ErrNoInstances { return nil } else if err != nil { return err } machineId := machined.tag.Id() initialPortRanges, err := instances[0].Ports(machineId) if err != nil { return err } initialPorts := network.PortRangesToPorts(initialPortRanges) // Check which ports to open or to close. toOpen := Diff(machined.ports, initialPorts) toClose := Diff(initialPorts, machined.ports) if len(toOpen) > 0 { logger.Infof("opening instance ports %v for %q", toOpen, machined.tag) if err := instances[0].OpenPorts(machineId, network.PortsToPortRanges(toOpen)); err != nil { // TODO(mue) Add local retry logic. return err } network.SortPorts(toOpen) } if len(toClose) > 0 { logger.Infof("closing instance ports %v for %q", toClose, machined.tag) if err := instances[0].ClosePorts(machineId, network.PortsToPortRanges(toClose)); err != nil { // TODO(mue) Add local retry logic. return err } network.SortPorts(toClose) } } return nil }
// convertEndpointsToPorts converts a slice of gwacl.InputEndpoint into a slice of network.PortRange. func convertEndpointsToPortRanges(endpoints []gwacl.InputEndpoint) []network.PortRange { // group ports by prefix on the endpoint name portSets := make(map[string][]network.Port) otherPorts := []network.Port{} for _, endpoint := range endpoints { port := network.Port{ Protocol: strings.ToLower(endpoint.Protocol), Number: endpoint.Port, } if strings.Contains(endpoint.Name, "_range_") { prefix := strings.Split(endpoint.Name, "_range_")[0] portSets[prefix] = append(portSets[prefix], port) } else { otherPorts = append(otherPorts, port) } } portRanges := []network.PortRange{} // convert port sets into port ranges for _, ports := range portSets { portRanges = append(portRanges, network.CollapsePorts(ports)...) } portRanges = append(portRanges, network.PortsToPortRanges(otherPorts)...) network.SortPortRanges(portRanges) return portRanges }
// flushInstancePorts opens and closes ports global on the machine. func (fw *Firewaller) flushInstancePorts(machined *machineData, toOpen, toClose []network.Port) error { // If there's nothing to do, do nothing. // This is important because when a machine is first created, // it will have no instance id but also no open ports - // InstanceId will fail but we don't care. if len(toOpen) == 0 && len(toClose) == 0 { return nil } m, err := machined.machine() if params.IsCodeNotFound(err) { return nil } if err != nil { return err } machineId := machined.tag.Id() instanceId, err := m.InstanceId() if err != nil { return err } instances, err := fw.environ.Instances([]instance.Id{instanceId}) if err != nil { return err } // Open and close the ports. if len(toOpen) > 0 { if err := instances[0].OpenPorts(machineId, network.PortsToPortRanges(toOpen)); err != nil { // TODO(mue) Add local retry logic. return err } network.SortPorts(toOpen) logger.Infof("opened ports %v on %q", toOpen, machined.tag) } if len(toClose) > 0 { if err := instances[0].ClosePorts(machineId, network.PortsToPortRanges(toClose)); err != nil { // TODO(mue) Add local retry logic. return err } network.SortPorts(toClose) logger.Infof("closed ports %v on %q", toClose, machined.tag) } return nil }
// reconcileGlobal compares the initially started watcher for machines, // units and services with the opened and closed ports globally and // opens and closes the appropriate ports for the whole environment. func (fw *Firewaller) reconcileGlobal() error { initialPortRanges, err := fw.environ.Ports() if err != nil { return err } initialPorts := network.PortRangesToPorts(initialPortRanges) collector := make(map[network.Port]bool) for _, unitd := range fw.unitds { if unitd.serviced.exposed { for _, port := range unitd.ports { collector[port] = true } } } wantedPorts := []network.Port{} for port := range collector { wantedPorts = append(wantedPorts, port) } // Check which ports to open or to close. toOpen := Diff(wantedPorts, initialPorts) toClose := Diff(initialPorts, wantedPorts) if len(toOpen) > 0 { logger.Infof("opening global ports %v", toOpen) if err := fw.environ.OpenPorts(network.PortsToPortRanges(toOpen)); err != nil { return err } network.SortPorts(toOpen) } if len(toClose) > 0 { logger.Infof("closing global ports %v", toClose) if err := fw.environ.ClosePorts(network.PortsToPortRanges(toClose)); err != nil { return err } network.SortPorts(toClose) } return nil }