github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/uniter/runner/context/ports_test.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package context_test
     5  
     6  import (
     7  	envtesting "github.com/juju/testing"
     8  	jc "github.com/juju/testing/checkers"
     9  	gc "gopkg.in/check.v1"
    10  	"gopkg.in/juju/names.v2"
    11  
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/core/network"
    14  	"github.com/juju/juju/worker/uniter/runner/context"
    15  )
    16  
    17  type PortsSuite struct {
    18  	envtesting.IsolationSuite
    19  }
    20  
    21  var _ = gc.Suite(&PortsSuite{})
    22  
    23  func (s *PortsSuite) TestValidatePortRange(c *gc.C) {
    24  	tests := []struct {
    25  		about     string
    26  		proto     string
    27  		ports     []int
    28  		portRange network.PortRange
    29  		expectErr string
    30  	}{{
    31  		about:     "invalid range - 0-0/tcp",
    32  		proto:     "tcp",
    33  		ports:     []int{0, 0},
    34  		expectErr: "invalid port range 0-0/tcp",
    35  	}, {
    36  		about:     "invalid range - 0-1/tcp",
    37  		proto:     "tcp",
    38  		ports:     []int{0, 1},
    39  		expectErr: "invalid port range 0-1/tcp",
    40  	}, {
    41  		about:     "invalid range - -1-1/tcp",
    42  		proto:     "tcp",
    43  		ports:     []int{-1, 1},
    44  		expectErr: "invalid port range -1-1/tcp",
    45  	}, {
    46  		about:     "invalid range - 1-99999/tcp",
    47  		proto:     "tcp",
    48  		ports:     []int{1, 99999},
    49  		expectErr: "invalid port range 1-99999/tcp",
    50  	}, {
    51  		about:     "invalid range - 88888-99999/tcp",
    52  		proto:     "tcp",
    53  		ports:     []int{88888, 99999},
    54  		expectErr: "invalid port range 88888-99999/tcp",
    55  	}, {
    56  		about:     "invalid protocol - 1-65535/foo",
    57  		proto:     "foo",
    58  		ports:     []int{1, 65535},
    59  		expectErr: `invalid protocol "foo", expected "tcp", "udp", or "icmp"`,
    60  	}, {
    61  		about: "valid range - 100-200/udp",
    62  		proto: "UDP",
    63  		ports: []int{100, 200},
    64  		portRange: network.PortRange{
    65  			FromPort: 100,
    66  			ToPort:   200,
    67  			Protocol: "udp",
    68  		},
    69  	}, {
    70  		about: "valid single port - 100/tcp",
    71  		proto: "TCP",
    72  		ports: []int{100, 100},
    73  		portRange: network.PortRange{
    74  			FromPort: 100,
    75  			ToPort:   100,
    76  			Protocol: "tcp",
    77  		},
    78  	}}
    79  	for i, test := range tests {
    80  		c.Logf("test %d: %s", i, test.about)
    81  		portRange, err := context.ValidatePortRange(
    82  			test.proto,
    83  			test.ports[0],
    84  			test.ports[1],
    85  		)
    86  		if test.expectErr != "" {
    87  			c.Check(err, gc.ErrorMatches, test.expectErr)
    88  			c.Check(portRange, jc.DeepEquals, network.PortRange{})
    89  		} else {
    90  			c.Check(err, jc.ErrorIsNil)
    91  			c.Check(portRange, jc.DeepEquals, test.portRange)
    92  		}
    93  	}
    94  }
    95  
    96  func makeMachinePorts(
    97  	unitName, proto string, fromPort, toPort int,
    98  ) map[network.PortRange]params.RelationUnit {
    99  	result := make(map[network.PortRange]params.RelationUnit)
   100  	portRange := network.PortRange{
   101  		FromPort: fromPort,
   102  		ToPort:   toPort,
   103  		Protocol: proto,
   104  	}
   105  	unitTag := ""
   106  	if unitName != "invalid" {
   107  		unitTag = names.NewUnitTag(unitName).String()
   108  	} else {
   109  		unitTag = unitName
   110  	}
   111  	result[portRange] = params.RelationUnit{
   112  		Unit: unitTag,
   113  	}
   114  	return result
   115  }
   116  
   117  func makePendingPorts(
   118  	proto string, fromPort, toPort int, shouldOpen bool,
   119  ) map[context.PortRange]context.PortRangeInfo {
   120  	result := make(map[context.PortRange]context.PortRangeInfo)
   121  	portRange := network.PortRange{
   122  		FromPort: fromPort,
   123  		ToPort:   toPort,
   124  		Protocol: proto,
   125  	}
   126  	key := context.PortRange{
   127  		Ports:      portRange,
   128  		RelationId: -1,
   129  	}
   130  	result[key] = context.PortRangeInfo{
   131  		ShouldOpen: shouldOpen,
   132  	}
   133  	return result
   134  }
   135  
   136  type portsTest struct {
   137  	about         string
   138  	proto         string
   139  	ports         []int
   140  	machinePorts  map[network.PortRange]params.RelationUnit
   141  	pendingPorts  map[context.PortRange]context.PortRangeInfo
   142  	expectErr     string
   143  	expectPending map[context.PortRange]context.PortRangeInfo
   144  }
   145  
   146  func (p portsTest) withDefaults(proto string, fromPort, toPort int) portsTest {
   147  	if p.proto == "" {
   148  		p.proto = proto
   149  	}
   150  	if len(p.ports) != 2 {
   151  		p.ports = []int{fromPort, toPort}
   152  	}
   153  	if p.pendingPorts == nil {
   154  		p.pendingPorts = make(map[context.PortRange]context.PortRangeInfo)
   155  	}
   156  	return p
   157  }
   158  
   159  func (s *PortsSuite) TestTryOpenPorts(c *gc.C) {
   160  	tests := []portsTest{{
   161  		about:     "invalid port range",
   162  		ports:     []int{0, 0},
   163  		expectErr: "invalid port range 0-0/tcp",
   164  	}, {
   165  		about:     "invalid protocol - 10-20/foo",
   166  		proto:     "foo",
   167  		expectErr: `invalid protocol "foo", expected "tcp", "udp", or "icmp"`,
   168  	}, {
   169  		about:         "open a new range (no machine ports yet)",
   170  		expectPending: makePendingPorts("tcp", 10, 20, true),
   171  	}, {
   172  		about:         "open an existing range (ignored)",
   173  		machinePorts:  makeMachinePorts("u/0", "tcp", 10, 20),
   174  		expectPending: map[context.PortRange]context.PortRangeInfo{},
   175  	}, {
   176  		about:         "open a range pending to be closed already",
   177  		pendingPorts:  makePendingPorts("tcp", 10, 20, false),
   178  		expectPending: makePendingPorts("tcp", 10, 20, true),
   179  	}, {
   180  		about:         "open a range pending to be opened already (ignored)",
   181  		pendingPorts:  makePendingPorts("tcp", 10, 20, true),
   182  		expectPending: makePendingPorts("tcp", 10, 20, true),
   183  	}, {
   184  		about:        "try opening a range when machine ports has invalid unit tag",
   185  		machinePorts: makeMachinePorts("invalid", "tcp", 80, 90),
   186  		expectErr:    `machine ports 80-90/tcp contain invalid unit tag: "invalid" is not a valid tag`,
   187  	}, {
   188  		about:        "try opening a range conflicting with another unit",
   189  		machinePorts: makeMachinePorts("u/1", "tcp", 10, 20),
   190  		expectErr:    `cannot open 10-20/tcp \(unit "u/0"\): conflicts with existing 10-20/tcp \(unit "u/1"\)`,
   191  	}, {
   192  		about:         "open a range conflicting with the same unit (ignored)",
   193  		machinePorts:  makeMachinePorts("u/0", "tcp", 10, 20),
   194  		expectPending: map[context.PortRange]context.PortRangeInfo{},
   195  	}, {
   196  		about:        "try opening a range conflicting with another pending range",
   197  		pendingPorts: makePendingPorts("tcp", 5, 25, true),
   198  		expectErr:    `cannot open 10-20/tcp \(unit "u/0"\): conflicts with 5-25/tcp requested earlier`,
   199  	}}
   200  	for i, test := range tests {
   201  		c.Logf("test %d: %s", i, test.about)
   202  
   203  		test = test.withDefaults("tcp", 10, 20)
   204  		err := context.TryOpenPorts(
   205  			test.proto,
   206  			test.ports[0],
   207  			test.ports[1],
   208  			names.NewUnitTag("u/0"),
   209  			test.machinePorts,
   210  			test.pendingPorts,
   211  		)
   212  		if test.expectErr != "" {
   213  			c.Check(err, gc.ErrorMatches, test.expectErr)
   214  		} else {
   215  			c.Check(err, jc.ErrorIsNil)
   216  			c.Check(test.pendingPorts, jc.DeepEquals, test.expectPending)
   217  		}
   218  	}
   219  }
   220  
   221  func (s *PortsSuite) TestTryClosePorts(c *gc.C) {
   222  	tests := []portsTest{{
   223  		about:     "invalid port range",
   224  		ports:     []int{0, 0},
   225  		expectErr: "invalid port range 0-0/tcp",
   226  	}, {
   227  		about:     "invalid protocol - 10-20/foo",
   228  		proto:     "foo",
   229  		expectErr: `invalid protocol "foo", expected "tcp", "udp", or "icmp"`,
   230  	}, {
   231  		about:         "close a new range (no machine ports yet; ignored)",
   232  		expectPending: map[context.PortRange]context.PortRangeInfo{},
   233  	}, {
   234  		about:         "close an existing range",
   235  		machinePorts:  makeMachinePorts("u/0", "tcp", 10, 20),
   236  		expectPending: makePendingPorts("tcp", 10, 20, false),
   237  	}, {
   238  		about:         "close a range pending to be opened already (removed from pending)",
   239  		pendingPorts:  makePendingPorts("tcp", 10, 20, true),
   240  		expectPending: map[context.PortRange]context.PortRangeInfo{},
   241  	}, {
   242  		about:         "close a range pending to be closed already (ignored)",
   243  		pendingPorts:  makePendingPorts("tcp", 10, 20, false),
   244  		expectPending: makePendingPorts("tcp", 10, 20, false),
   245  	}, {
   246  		about:        "try closing an existing range when machine ports has invalid unit tag",
   247  		machinePorts: makeMachinePorts("invalid", "tcp", 10, 20),
   248  		expectErr:    `machine ports 10-20/tcp contain invalid unit tag: "invalid" is not a valid tag`,
   249  	}, {
   250  		about:        "try closing a range of another unit",
   251  		machinePorts: makeMachinePorts("u/1", "tcp", 10, 20),
   252  		expectErr:    `cannot close 10-20/tcp \(opened by "u/1"\) from "u/0"`,
   253  	}}
   254  	for i, test := range tests {
   255  		c.Logf("test %d: %s", i, test.about)
   256  
   257  		test = test.withDefaults("tcp", 10, 20)
   258  		err := context.TryClosePorts(
   259  			test.proto,
   260  			test.ports[0],
   261  			test.ports[1],
   262  			names.NewUnitTag("u/0"),
   263  			test.machinePorts,
   264  			test.pendingPorts,
   265  		)
   266  		if test.expectErr != "" {
   267  			c.Check(err, gc.ErrorMatches, test.expectErr)
   268  		} else {
   269  			c.Check(err, jc.ErrorIsNil)
   270  			c.Check(test.pendingPorts, jc.DeepEquals, test.expectPending)
   271  		}
   272  	}
   273  }