// 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.CollapsePorts(otherPorts)...) network.SortPortRanges(portRanges) return portRanges }
func (*PortSuite) TestCollapsePorts(c *gc.C) { testCases := []struct { about string ports []network.Port expected []network.PortRange }{{ "single port", []network.Port{{"tcp", 80}}, []network.PortRange{{80, 80, "tcp"}}, }, { "continuous port range", []network.Port{{"tcp", 80}, {"tcp", 81}, {"tcp", 82}, {"tcp", 83}}, []network.PortRange{{80, 83, "tcp"}}, }, { "non-continuous port range", []network.Port{{"tcp", 80}, {"tcp", 81}, {"tcp", 82}, {"tcp", 84}, {"tcp", 85}}, []network.PortRange{{80, 82, "tcp"}, {84, 85, "tcp"}}, }, { "non-continuous port range (udp vs tcp)", []network.Port{{"tcp", 80}, {"tcp", 81}, {"tcp", 82}, {"udp", 84}, {"tcp", 83}}, []network.PortRange{{80, 83, "tcp"}, {84, 84, "udp"}}, }, } for i, t := range testCases { c.Logf("test %d: %s", i, t.about) c.Assert(network.CollapsePorts(t.ports), gc.DeepEquals, t.expected) } }
// Helper method to get port from the given firewall rules func getPorts(envName string, rules []cloudapi.FirewallRule) []network.PortRange { portRanges := []network.PortRange{} for _, r := range rules { rule := r.Rule if r.Enabled && strings.HasPrefix(rule, "FROM tag "+envName) && strings.Contains(rule, "PORT") { if firewallSinglePortRule.MatchString(rule) { parts := firewallSinglePortRule.FindStringSubmatch(rule) if len(parts) != 3 { continue } protocol := parts[1] n, _ := strconv.Atoi(parts[2]) portRanges = append(portRanges, network.PortRange{Protocol: protocol, FromPort: n, ToPort: n}) } else if firewallMultiPortRule.MatchString(rule) { parts := firewallMultiPortRule.FindStringSubmatch(rule) if len(parts) != 3 { continue } protocol := parts[1] ports := []network.Port{} portStrings := strings.Split(parts[2], " AND ") for _, portString := range portStrings { portString = portString[strings.LastIndex(portString, "PORT")+5:] port, _ := strconv.Atoi(portString) ports = append(ports, network.Port{protocol, port}) } portRanges = append(portRanges, network.CollapsePorts(ports)...) } } } network.SortPortRanges(portRanges) return portRanges }
func validateUnitPorts(st *State, unit *Unit) ( skippedRanges int, mergedRanges []network.PortRange, validRanges []PortRange, ) { // Collapse individual ports into port ranges. mergedRanges = network.CollapsePorts(networkPorts(unit.doc.Ports)) upgradesLogger.Debugf("merged raw port ranges for unit %q: %v", unit, mergedRanges) skippedRanges = 0 // Validate each merged range. for _, mergedRange := range mergedRanges { // Convert to state.PortRange, without validation. stateRange := PortRange{ UnitName: unit.Name(), FromPort: mergedRange.FromPort, ToPort: mergedRange.ToPort, Protocol: strings.ToLower(mergedRange.Protocol), } // Validate the constructed range. if err := stateRange.Validate(); err != nil { // Don't give up yet - log it, but try to sanitize first. upgradesLogger.Warningf( "merged port range %v invalid; trying to sanitize bounds", stateRange, ) stateRange = stateRange.SanitizeBounds() upgradesLogger.Debugf( "merged range %v sanitized as %v", mergedRange, stateRange, ) // Now try again. if err := stateRange.Validate(); err != nil { // Despite trying, the converted port range is still invalid, // just skip the migration and log it. upgradesLogger.Warningf( "cannot migrate unit %q's invalid ports %v: %v (skipping)", unit, stateRange, err, ) skippedRanges++ continue } } validRanges = append(validRanges, stateRange) } upgradesLogger.Debugf("unit %q valid merged ranges: %v", unit, validRanges) return skippedRanges, mergedRanges, validRanges }
func (*PortRangeSuite) TestCollapsePorts(c *gc.C) { testCases := []struct { about string ports []network.Port expected []network.PortRange }{{ "single port", []network.Port{{"tcp", 80}}, []network.PortRange{{80, 80, "tcp"}}, }, { "continuous port range (increasing)", []network.Port{{"tcp", 80}, {"tcp", 81}, {"tcp", 82}, {"tcp", 83}}, []network.PortRange{{80, 83, "tcp"}}, }, { "continuous port range (decreasing)", []network.Port{{"tcp", 83}, {"tcp", 82}, {"tcp", 81}, {"tcp", 80}}, []network.PortRange{{80, 83, "tcp"}}, }, { "non-continuous port range (increasing)", []network.Port{{"tcp", 80}, {"tcp", 81}, {"tcp", 82}, {"tcp", 84}, {"tcp", 85}}, []network.PortRange{{80, 82, "tcp"}, {84, 85, "tcp"}}, }, { "non-continuous port range (decreasing)", []network.Port{{"tcp", 85}, {"tcp", 84}, {"tcp", 82}, {"tcp", 81}, {"tcp", 80}}, []network.PortRange{{80, 82, "tcp"}, {84, 85, "tcp"}}, }, { "alternating tcp / udp ports (increasing)", []network.Port{{"tcp", 80}, {"udp", 81}, {"tcp", 82}, {"udp", 83}, {"tcp", 84}}, []network.PortRange{{80, 80, "tcp"}, {82, 82, "tcp"}, {84, 84, "tcp"}, {81, 81, "udp"}, {83, 83, "udp"}}, }, { "alternating tcp / udp ports (decreasing)", []network.Port{{"tcp", 84}, {"udp", 83}, {"tcp", 82}, {"udp", 81}, {"tcp", 80}}, []network.PortRange{{80, 80, "tcp"}, {82, 82, "tcp"}, {84, 84, "tcp"}, {81, 81, "udp"}, {83, 83, "udp"}}, }, { "non-continuous port range (udp vs tcp - increasing)", []network.Port{{"tcp", 80}, {"tcp", 81}, {"tcp", 82}, {"udp", 84}, {"tcp", 83}}, []network.PortRange{{80, 83, "tcp"}, {84, 84, "udp"}}, }, { "non-continuous port range (udp vs tcp - decreasing)", []network.Port{{"tcp", 83}, {"udp", 84}, {"tcp", 82}, {"tcp", 81}, {"tcp", 80}}, []network.PortRange{{80, 83, "tcp"}, {84, 84, "udp"}}, }} for i, t := range testCases { c.Logf("test %d: %s", i, t.about) c.Check(network.CollapsePorts(t.ports), jc.DeepEquals, t.expected) } }