// 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(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(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 } tag, err := names.ParseTag(machined.tag, names.MachineTagKind) if err != nil { return err } machineId := tag.Id() initialPorts, err := instances[0].Ports(machineId) if err != nil { return err } // 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, 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, toClose); err != nil { // TODO(mue) Add local retry logic. return err } network.SortPorts(toClose) } } return nil }
// 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 } tag, err := names.ParseTag(machined.tag, names.MachineTagKind) if err != nil { return err } machineId := 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, 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, 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 }
// Ports is specified in the Instance interface. func (azInstance *azureInstance) Ports(machineId string) (ports []network.Port, err error) { err = azInstance.apiCall(false, func(context *azureManagementContext) error { ports, err = azInstance.listPorts(context) return err }) if ports != nil { network.SortPorts(ports) } return ports, err }
// assertEnvironPorts retrieves the open ports of environment and compares them // to the expected. func (s *FirewallerSuite) assertEnvironPorts(c *gc.C, expected []network.Port) { s.BackingState.StartSync() start := time.Now() for { got, err := s.Environ.Ports() if err != nil { c.Fatal(err) return } network.SortPorts(got) network.SortPorts(expected) if reflect.DeepEqual(got, expected) { c.Succeed() return } if time.Since(start) > coretesting.LongWait { c.Fatalf("timed out: expected %q; got %q", expected, got) return } time.Sleep(coretesting.ShortWait) } }
func (s *instanceSuite) testPorts(c *gc.C, maskStateServerPorts bool) { // Update the role's endpoints by hand. configSetNetwork(s.role).InputEndpoints = &[]gwacl.InputEndpoint{{ LocalPort: 223, Protocol: "udp", Name: "test223", Port: 2123, }, { LocalPort: 123, Protocol: "udp", Name: "test123", Port: 1123, }, { LocalPort: 456, Protocol: "tcp", Name: "test456", Port: 4456, }, { LocalPort: s.env.Config().StatePort(), Protocol: "tcp", Name: "stateserver", Port: s.env.Config().StatePort(), }, { LocalPort: s.env.Config().APIPort(), Protocol: "tcp", Name: "apiserver", Port: s.env.Config().APIPort(), }} responses := preparePortChangeConversation(c, s.role) record := gwacl.PatchManagementAPIResponses(responses) s.instance.maskStateServerPorts = maskStateServerPorts ports, err := s.instance.Ports("machine-id") c.Assert(err, gc.IsNil) assertPortChangeConversation(c, *record, []expectedRequest{ {"GET", ".*/deployments/deployment-one/roles/role-one"}, // GetRole }) expected := []network.Port{ {Number: 4456, Protocol: "tcp"}, {Number: 1123, Protocol: "udp"}, {Number: 2123, Protocol: "udp"}, } if !maskStateServerPorts { expected = append(expected, network.Port{Number: s.env.Config().StatePort(), Protocol: "tcp"}) expected = append(expected, network.Port{Number: s.env.Config().APIPort(), Protocol: "tcp"}) network.SortPorts(expected) } c.Check(ports, gc.DeepEquals, expected) }
// 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 }
// Helper method to get port from the given firewall rules func getPorts(env *joyentEnviron, rules []cloudapi.FirewallRule) []network.Port { ports := []network.Port{} for _, r := range rules { rule := r.Rule if r.Enabled && strings.HasPrefix(rule, "FROM tag "+env.Name()) && strings.Contains(rule, "PORT") { p := rule[strings.Index(rule, "ALLOW")+6 : strings.Index(rule, "PORT")-1] n, _ := strconv.Atoi(rule[strings.LastIndex(rule, " ")+1:]) port := network.Port{Protocol: p, Number: n} ports = append(ports, port) } } network.SortPorts(ports) return ports }
func (e *environ) Ports() (ports []network.Port, err error) { if mode := e.ecfg().FirewallMode(); mode != config.FwGlobal { return nil, fmt.Errorf("invalid firewall mode %q for retrieving ports from environment", mode) } estate, err := e.state() if err != nil { return nil, err } estate.mu.Lock() defer estate.mu.Unlock() for p := range estate.globalPorts { ports = append(ports, p) } network.SortPorts(ports) return }
func (inst *dummyInstance) Ports(machineId string) (ports []network.Port, err error) { defer delay() if inst.firewallMode != config.FwInstance { return nil, fmt.Errorf("invalid firewall mode %q for retrieving ports from instance", inst.firewallMode) } if inst.machineId != machineId { panic(fmt.Errorf("Ports with mismatched machine id, expected %q got %q", inst.machineId, machineId)) } inst.state.mu.Lock() defer inst.state.mu.Unlock() for p := range inst.ports { ports = append(ports, p) } network.SortPorts(ports) return }
// OpenedPorts returns a slice containing the open ports of the unit. func (u *Unit) OpenedPorts() []network.Port { ports := append([]network.Port{}, u.doc.Ports...) network.SortPorts(ports) return ports }