diff --git a/provider/azure/environ.go b/provider/azure/environ.go index 76b53406a4b..ec156b276d7 100644 --- a/provider/azure/environ.go +++ b/provider/azure/environ.go @@ -778,6 +778,10 @@ func (env *azureEnviron) newOSDisk(sourceImageName string) *gwacl.OSVirtualHardD // getInitialEndpoints returns a slice of the endpoints every instance should have open // (ssh port, etc). func (env *azureEnviron) getInitialEndpoints(stateServer bool) []gwacl.InputEndpoint { + // TODO(axw) either proxy ssh traffic through one of the + // randomly chosen VMs to the internal address, or otherwise + // don't load balance SSH and provide a way of getting the + // local port. cfg := env.Config() endpoints := []gwacl.InputEndpoint{{ LocalPort: 22, @@ -787,6 +791,11 @@ func (env *azureEnviron) getInitialEndpoints(stateServer bool) []gwacl.InputEndp }} if stateServer { endpoints = append(endpoints, []gwacl.InputEndpoint{{ + LocalPort: cfg.StatePort(), + Port: cfg.StatePort(), + Protocol: "tcp", + Name: "stateport", + }, { LocalPort: cfg.APIPort(), Port: cfg.APIPort(), Protocol: "tcp", diff --git a/provider/azure/environ_test.go b/provider/azure/environ_test.go index 7d49645d251..1e74614dae9 100644 --- a/provider/azure/environ_test.go +++ b/provider/azure/environ_test.go @@ -1158,6 +1158,11 @@ func (s *environSuite) TestInitialPorts(c *gc.C) { // Only role2 should report opened state server ports via the Ports method. dummyRole := *role1 configSetNetwork(&dummyRole).InputEndpoints = &[]gwacl.InputEndpoint{{ + LocalPort: env.Config().StatePort(), + Protocol: "tcp", + Name: "stateserver", + Port: env.Config().StatePort(), + }, { LocalPort: env.Config().APIPort(), Protocol: "tcp", Name: "apiserver", @@ -1172,7 +1177,7 @@ func (s *environSuite) TestInitialPorts(c *gc.C) { for _, port := range ports { portmap[port.Number] = true } - return portmap[env.Config().APIPort()] + return portmap[env.Config().StatePort()] && portmap[env.Config().APIPort()] } c.Check(inst1, gc.Not(jc.Satisfies), reportsStateServerPorts) c.Check(inst2, jc.Satisfies, reportsStateServerPorts) @@ -1242,7 +1247,13 @@ func (*environSuite) testNewRole(c *gc.C, stateServer bool) { c.Check(sshEndpoint.Protocol, gc.Equals, "tcp") if stateServer { - // There should be an endpoint for the API port. + // There's also an endpoint for the state (mongodb) port. + stateEndpoint, ok := endpoints[env.Config().StatePort()] + c.Assert(ok, gc.Equals, true) + c.Check(stateEndpoint.LocalPort, gc.Equals, env.Config().StatePort()) + c.Check(stateEndpoint.Protocol, gc.Equals, "tcp") + + // And one for the API port. apiEndpoint, ok := endpoints[env.Config().APIPort()] c.Assert(ok, gc.Equals, true) c.Check(apiEndpoint.LocalPort, gc.Equals, env.Config().APIPort()) diff --git a/provider/azure/instance_test.go b/provider/azure/instance_test.go index b7255fd5cfc..b4a3f280113 100644 --- a/provider/azure/instance_test.go +++ b/provider/azure/instance_test.go @@ -353,6 +353,11 @@ func (s *instanceSuite) testPorts(c *gc.C, maskStateServerPorts bool) { 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", @@ -375,6 +380,7 @@ func (s *instanceSuite) testPorts(c *gc.C, maskStateServerPorts bool) { {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) } diff --git a/provider/ec2/ec2.go b/provider/ec2/ec2.go index 0a9bcd434b3..e506e787a64 100644 --- a/provider/ec2/ec2.go +++ b/provider/ec2/ec2.go @@ -604,7 +604,7 @@ func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Ins } logger.Debugf("ec2 user data; %d bytes", len(userData)) cfg := e.Config() - groups, err := e.setUpGroups(args.MachineConfig.MachineId, cfg.APIPort()) + groups, err := e.setUpGroups(args.MachineConfig.MachineId, cfg.StatePort(), cfg.APIPort()) if err != nil { return nil, nil, nil, fmt.Errorf("cannot set up groups: %v", err) } @@ -1079,7 +1079,7 @@ func (inst *ec2Instance) Ports(machineId string) ([]network.Port, error) { // other instances that might be running on the same EC2 account. In // addition, a specific machine security group is created for each // machine, so that its firewall rules can be configured per machine. -func (e *environ) setUpGroups(machineId string, apiPort int) ([]ec2.SecurityGroup, error) { +func (e *environ) setUpGroups(machineId string, statePort, apiPort int) ([]ec2.SecurityGroup, error) { jujuGroup, err := e.ensureGroup(e.jujuGroupName(), []ec2.IPPerm{ { @@ -1088,6 +1088,12 @@ func (e *environ) setUpGroups(machineId string, apiPort int) ([]ec2.SecurityGrou ToPort: 22, SourceIPs: []string{"0.0.0.0/0"}, }, + { + Protocol: "tcp", + FromPort: statePort, + ToPort: statePort, + SourceIPs: []string{"0.0.0.0/0"}, + }, { Protocol: "tcp", FromPort: apiPort, diff --git a/provider/ec2/live_test.go b/provider/ec2/live_test.go index 5b3a4338bb1..554821a30ad 100644 --- a/provider/ec2/live_test.go +++ b/provider/ec2/live_test.go @@ -226,8 +226,9 @@ func (t *LiveTests) TestInstanceGroups(c *gc.C) { // that the unneeded permission that we added earlier // has been deleted). perms := info[0].IPPerms - c.Assert(perms, gc.HasLen, 5) + c.Assert(perms, gc.HasLen, 6) checkPortAllowed(c, perms, 22) // SSH + checkPortAllowed(c, perms, coretesting.FakeConfig()["state-port"].(int)) checkPortAllowed(c, perms, coretesting.FakeConfig()["api-port"].(int)) checkSecurityGroupAllowed(c, perms, groups[0]) diff --git a/provider/openstack/export_test.go b/provider/openstack/export_test.go index a55492c9087..c507ca3614d 100644 --- a/provider/openstack/export_test.go +++ b/provider/openstack/export_test.go @@ -296,8 +296,8 @@ func SetUseFloatingIP(e environs.Environ, val bool) { env.ecfg().attrs["use-floating-ip"] = val } -func SetUpGlobalGroup(e environs.Environ, name string, apiPort int) (nova.SecurityGroup, error) { - return e.(*environ).setUpGlobalGroup(name, apiPort) +func SetUpGlobalGroup(e environs.Environ, name string, statePort, apiPort int) (nova.SecurityGroup, error) { + return e.(*environ).setUpGlobalGroup(name, statePort, apiPort) } func EnsureGroup(e environs.Environ, name string, rules []nova.RuleInfo) (nova.SecurityGroup, error) { diff --git a/provider/openstack/live_test.go b/provider/openstack/live_test.go index fd82f5ca046..4bd6b7c40c7 100644 --- a/provider/openstack/live_test.go +++ b/provider/openstack/live_test.go @@ -178,15 +178,17 @@ func (t *LiveTests) TestSetupGlobalGroupExposesCorrectPorts(c *gc.C) { } cleanup() defer cleanup() - apiPort := 34567 // Default 17070 - group, err := openstack.SetUpGlobalGroup(t.Env, groupName, apiPort) + statePort := 12345 // Default 37017 + apiPort := 34567 // Default 17070 + group, err := openstack.SetUpGlobalGroup(t.Env, groupName, statePort, apiPort) c.Assert(err, gc.IsNil) c.Assert(err, gc.IsNil) - // We default to exporting 22, apiPort, and icmp/udp/tcp on + // We default to exporting 22, statePort, apiPort, and icmp/udp/tcp on // all ports to other machines inside the same group // TODO(jam): 2013-09-18 http://pad.lv/1227142 - // We shouldn't be exposing the API port on all the machines - // that *aren't* hosting the state server. + // We shouldn't be exposing the API and State ports on all the machines + // that *aren't* hosting the state server. (And once we finish + // client-via-API we can disable the State port as well.) stringRules := make([]string, 0, len(group.Rules)) for _, rule := range group.Rules { ruleStr := fmt.Sprintf("%s %d %d %q %q", @@ -201,6 +203,7 @@ func (t *LiveTests) TestSetupGlobalGroupExposesCorrectPorts(c *gc.C) { // We don't care about the ordering, so we sort the result, and compare it. expectedRules := []string{ `tcp 22 22 "0.0.0.0/0" ""`, + fmt.Sprintf(`tcp %d %d "0.0.0.0/0" ""`, statePort, statePort), fmt.Sprintf(`tcp %d %d "0.0.0.0/0" ""`, apiPort, apiPort), fmt.Sprintf(`tcp 1 65535 "" "%s"`, groupName), fmt.Sprintf(`udp 1 65535 "" "%s"`, groupName), diff --git a/provider/openstack/provider.go b/provider/openstack/provider.go index b5a543a2ba6..f8441bedba4 100644 --- a/provider/openstack/provider.go +++ b/provider/openstack/provider.go @@ -959,7 +959,7 @@ func (e *environ) StartInstance(args environs.StartInstanceParams) (instance.Ins } } cfg := e.Config() - groups, err := e.setUpGroups(args.MachineConfig.MachineId, cfg.APIPort()) + groups, err := e.setUpGroups(args.MachineConfig.MachineId, cfg.StatePort(), cfg.APIPort()) if err != nil { return nil, nil, nil, fmt.Errorf("cannot set up groups: %v", err) } @@ -1296,7 +1296,7 @@ func (e *environ) Provider() environs.EnvironProvider { return &providerInstance } -func (e *environ) setUpGlobalGroup(groupName string, apiPort int) (nova.SecurityGroup, error) { +func (e *environ) setUpGlobalGroup(groupName string, statePort, apiPort int) (nova.SecurityGroup, error) { return e.ensureGroup(groupName, []nova.RuleInfo{ { @@ -1305,6 +1305,12 @@ func (e *environ) setUpGlobalGroup(groupName string, apiPort int) (nova.Security ToPort: 22, Cidr: "0.0.0.0/0", }, + { + IPProtocol: "tcp", + FromPort: statePort, + ToPort: statePort, + Cidr: "0.0.0.0/0", + }, { IPProtocol: "tcp", FromPort: apiPort, @@ -1340,8 +1346,8 @@ func (e *environ) setUpGlobalGroup(groupName string, apiPort int) (nova.Security // Note: ideally we'd have a better way to determine group membership so that 2 // people that happen to share an openstack account and name their environment // "openstack" don't end up destroying each other's machines. -func (e *environ) setUpGroups(machineId string, apiPort int) ([]nova.SecurityGroup, error) { - jujuGroup, err := e.setUpGlobalGroup(e.jujuGroupName(), apiPort) +func (e *environ) setUpGroups(machineId string, statePort, apiPort int) ([]nova.SecurityGroup, error) { + jujuGroup, err := e.setUpGlobalGroup(e.jujuGroupName(), statePort, apiPort) if err != nil { return nil, err }