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

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Copyright 2014 Cloudbase Solutions SRL
     3  // Licensed under the AGPLv3, see LICENCE file for details.
     4  
     5  package jujuc_test
     6  
     7  import (
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/cmd/cmdtesting"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/core/network"
    17  	"github.com/juju/juju/worker/uniter/runner/jujuc"
    18  )
    19  
    20  type PortsSuite struct {
    21  	ContextSuite
    22  }
    23  
    24  var _ = gc.Suite(&PortsSuite{})
    25  
    26  var portsTests = []struct {
    27  	cmd    []string
    28  	expect []network.PortRange
    29  }{
    30  	{[]string{"open-port", "80"}, makeRanges("80/tcp")},
    31  	{[]string{"open-port", "99/tcp"}, makeRanges("80/tcp", "99/tcp")},
    32  	{[]string{"open-port", "100-200"}, makeRanges("80/tcp", "99/tcp", "100-200/tcp")},
    33  	{[]string{"open-port", "443/udp"}, makeRanges("80/tcp", "99/tcp", "100-200/tcp", "443/udp")},
    34  	{[]string{"close-port", "80/TCP"}, makeRanges("99/tcp", "100-200/tcp", "443/udp")},
    35  	{[]string{"close-port", "100-200/tcP"}, makeRanges("99/tcp", "443/udp")},
    36  	{[]string{"close-port", "443"}, makeRanges("99/tcp", "443/udp")},
    37  	{[]string{"close-port", "443/udp"}, makeRanges("99/tcp")},
    38  	{[]string{"open-port", "123/udp"}, makeRanges("99/tcp", "123/udp")},
    39  	{[]string{"close-port", "9999/UDP"}, makeRanges("99/tcp", "123/udp")},
    40  	{[]string{"open-port", "icmp"}, makeRanges("icmp", "99/tcp", "123/udp")},
    41  }
    42  
    43  func makeRanges(stringRanges ...string) []network.PortRange {
    44  	var results []network.PortRange
    45  	for _, s := range stringRanges {
    46  		if s == "icmp" {
    47  			results = append(results, network.PortRange{
    48  				FromPort: -1,
    49  				ToPort:   -1,
    50  				Protocol: "icmp",
    51  			})
    52  			continue
    53  		}
    54  		if strings.Contains(s, "-") {
    55  			parts := strings.Split(s, "-")
    56  			fromPort, _ := strconv.Atoi(parts[0])
    57  			parts = strings.Split(parts[1], "/")
    58  			toPort, _ := strconv.Atoi(parts[0])
    59  			proto := parts[1]
    60  			results = append(results, network.PortRange{
    61  				FromPort: fromPort,
    62  				ToPort:   toPort,
    63  				Protocol: proto,
    64  			})
    65  		} else {
    66  			parts := strings.Split(s, "/")
    67  			port, _ := strconv.Atoi(parts[0])
    68  			proto := parts[1]
    69  			results = append(results, network.PortRange{
    70  				FromPort: port,
    71  				ToPort:   port,
    72  				Protocol: proto,
    73  			})
    74  		}
    75  	}
    76  	network.SortPortRanges(results)
    77  	return results
    78  }
    79  
    80  func (s *PortsSuite) TestOpenClose(c *gc.C) {
    81  	hctx := s.GetHookContext(c, -1, "")
    82  	for _, t := range portsTests {
    83  		com, err := jujuc.NewCommand(hctx, cmdString(t.cmd[0]))
    84  		c.Assert(err, jc.ErrorIsNil)
    85  		ctx := cmdtesting.Context(c)
    86  		code := cmd.Main(jujuc.NewJujucCommandWrappedForTest(com), ctx, t.cmd[1:])
    87  		c.Check(code, gc.Equals, 0)
    88  		c.Assert(bufferString(ctx.Stdout), gc.Equals, "")
    89  		c.Assert(bufferString(ctx.Stderr), gc.Equals, "")
    90  		hctx.info.CheckPorts(c, t.expect)
    91  	}
    92  }
    93  
    94  var badPortsTests = []struct {
    95  	args []string
    96  	err  string
    97  }{
    98  	{nil, "no port or range specified"},
    99  	{[]string{"0"}, `port must be in the range \[1, 65535\]; got "0"`},
   100  	{[]string{"65536"}, `port must be in the range \[1, 65535\]; got "65536"`},
   101  	{[]string{"two"}, `expected <port>\[/<protocol>\] or <from>-<to>\[/<protocol>\] or icmp; got "two"`},
   102  	{[]string{"80/http"}, `protocol must be "tcp", "udp", or "icmp"; got "http"`},
   103  	{[]string{"blah/blah/blah"}, `expected <port>\[/<protocol>\] or <from>-<to>\[/<protocol>\] or icmp; got "blah/blah/blah"`},
   104  	{[]string{"123", "haha"}, `unrecognized args: \["haha"\]`},
   105  	{[]string{"1-0"}, `invalid port range 1-0/tcp; expected fromPort <= toPort`},
   106  	{[]string{"-42"}, `option provided but not defined: -4`},
   107  	{[]string{"99999/UDP"}, `port must be in the range \[1, 65535\]; got "99999"`},
   108  	{[]string{"9999/foo"}, `protocol must be "tcp", "udp", or "icmp"; got "foo"`},
   109  	{[]string{"80-90/http"}, `protocol must be "tcp", "udp", or "icmp"; got "http"`},
   110  	{[]string{"20-10/tcp"}, `invalid port range 20-10/tcp; expected fromPort <= toPort`},
   111  	{[]string{"80/icmp"}, `protocol "icmp" doesn't support any ports; got "80"`},
   112  }
   113  
   114  func (s *PortsSuite) TestBadArgs(c *gc.C) {
   115  	for _, name := range []string{"open-port", "close-port"} {
   116  		for _, t := range badPortsTests {
   117  			hctx := s.GetHookContext(c, -1, "")
   118  			com, err := jujuc.NewCommand(hctx, cmdString(name))
   119  			c.Assert(err, jc.ErrorIsNil)
   120  			err = cmdtesting.InitCommand(jujuc.NewJujucCommandWrappedForTest(com), t.args)
   121  			c.Assert(err, gc.ErrorMatches, t.err)
   122  		}
   123  	}
   124  }
   125  
   126  func (s *PortsSuite) TestHelp(c *gc.C) {
   127  	hctx := s.GetHookContext(c, -1, "")
   128  	open, err := jujuc.NewCommand(hctx, cmdString("open-port"))
   129  	c.Assert(err, jc.ErrorIsNil)
   130  	flags := cmdtesting.NewFlagSet()
   131  	c.Assert(string(open.Info().Help(flags)), gc.Equals, `
   132  Usage: open-port <port>[/<protocol>] or <from>-<to>[/<protocol>] or icmp
   133  
   134  Summary:
   135  register a port or range to open
   136  
   137  Details:
   138  The port range will only be open while the application is exposed.
   139  `[1:])
   140  
   141  	close, err := jujuc.NewCommand(hctx, cmdString("close-port"))
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	c.Assert(string(close.Info().Help(flags)), gc.Equals, `
   144  Usage: close-port <port>[/<protocol>] or <from>-<to>[/<protocol>] or icmp
   145  
   146  Summary:
   147  ensure a port or range is always closed
   148  `[1:])
   149  }
   150  
   151  // Since the deprecation warning gets output during Run, we really need
   152  // some valid commands to run
   153  var portsFormatDeprectaionTests = []struct {
   154  	cmd []string
   155  }{
   156  	{[]string{"open-port", "--format", "foo", "80"}},
   157  	{[]string{"close-port", "--format", "foo", "80/TCP"}},
   158  }
   159  
   160  func (s *PortsSuite) TestOpenCloseDeprecation(c *gc.C) {
   161  	hctx := s.GetHookContext(c, -1, "")
   162  	for _, t := range portsFormatDeprectaionTests {
   163  		name := t.cmd[0]
   164  		com, err := jujuc.NewCommand(hctx, cmdString(name))
   165  		c.Assert(err, jc.ErrorIsNil)
   166  		ctx := cmdtesting.Context(c)
   167  		code := cmd.Main(jujuc.NewJujucCommandWrappedForTest(com), ctx, t.cmd[1:])
   168  		c.Assert(code, gc.Equals, 0)
   169  		c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "")
   170  		c.Assert(cmdtesting.Stderr(ctx), gc.Equals, "--format flag deprecated for command \""+name+"\"")
   171  	}
   172  }