Skip to content

Commit 7dfbd61

Browse files
authored
Merge pull request juju#15225 from ycliuhw/open-port-per-unit4sidecar
juju#15225 This PR changes the application (vs machine) level opened ports to be grouped per unit for sidecar applications: - Allow open-port to happen from any unit, and Juju would open the ports (in the K8s service definition) that are the union of all ports that any unit has opened. So if unit/1 opened port 8080 and unit/2 opened port 4000, we'd tell K8s to open both. This would be unusual but supported. - Kind of the opposite for close-port: Juju would only close the port in the K8s service definition once all units had asked for that port to be closed. - Remove the check for is-leader. - Add model upgrades steps and model migration strategy to deal with the port ranges changed from application scope (`3.1.0`) to unit scope. ## Checklist - [x] Code style: imports ordered, good names, simple structure, etc - [x] Comments saying why design decisions were made - [x] Go unit tests, with comments saying what you're testing - [ ] ~[Integration tests](https://github.com/juju/juju/tree/develop/tests), with comments saying what you're testing~ - [ ] ~[doc.go](https://discourse.charmhub.io/t/readme-in-packages/451) added or updated in changed packages~ ## QA steps ```sh juju deploy prometheus-k8s --trust Located charm "prometheus-k8s" in charm-hub, revision 103 Deploying "prometheus-k8s" from charm-hub charm "prometheus-k8s", revision 103 in channel stable on [email protected]/stable juju scale-application prometheus-k8s 2 juju exec --unit prometheus-k8s/0 -- open-port 3000 juju exec --unit prometheus-k8s/1 -- open-port 3000 juju exec --unit prometheus-k8s/1 -- open-port 3001 juju exec --unit prometheus-k8s/0 -- opened-ports 3000/tcp juju exec --unit prometheus-k8s/1 -- opened-ports 3000/tcp 3001/tcp mkubectl -nt1 get service/prometheus-k8s -o json | jq '.spec.ports' [ { "name": "prometheus-k8s", "port": 9090, "protocol": "TCP", "targetPort": 9090 }, { "name": "juju-3000-tcp", "port": 3000, "protocol": "TCP", "targetPort": 3000 }, { "name": "juju-3001-tcp", "port": 3001, "protocol": "TCP", "targetPort": 3001 } ] juju exec --unit prometheus-k8s/1 -- close-port 3001 mkubectl -nt1 get service/prometheus-k8s -o json | jq '.spec.ports' [ { "name": "prometheus-k8s", "port": 9090, "protocol": "TCP", "targetPort": 9090 }, { "name": "juju-3000-tcp", "port": 3000, "protocol": "TCP", "targetPort": 3000 } ] juju exec --unit prometheus-k8s/1 -- close-port 3000 mkubectl -nt1 get service/prometheus-k8s -o json | jq '.spec.ports' [ { "name": "prometheus-k8s", "port": 9090, "protocol": "TCP", "targetPort": 9090 }, { "name": "juju-3000-tcp", "port": 3000, "protocol": "TCP", "targetPort": 3000 } ] juju exec --unit prometheus-k8s/0 -- close-port 3000 mkubectl -nt1 get service/prometheus-k8s -o json | jq '.spec.ports' [ { "name": "prometheus-k8s", "port": 9090, "protocol": "TCP", "targetPort": 9090 } ] ``` - upgrade controller from 3.1.0 -> 3.1.1 (application opened ports should be copied across all the units.) ```sh juju status --relations --color --storage -m k1:t1 Model Controller Cloud/Region Version SLA Timestamp t1 k1 microk8s/localhost 3.1.0 unsupported 21:54:23+11:00 App Version Status Scale Charm Channel Rev Address Exposed Message prometheus-k8s 2.33.5 active 2 prometheus-k8s stable 103 10.152.183.82 no Unit Workload Agent Address Ports Message prometheus-k8s/0* active idle 10.1.97.236 prometheus-k8s/1 active idle 10.1.97.238 Relation provider Requirer Interface Type Message prometheus-k8s:prometheus-peers prometheus-k8s:prometheus-peers prometheus_peers peer Storage Unit Storage ID Type Pool Mountpoint Size Status Message prometheus-k8s/0 database/0 filesystem kubernetes /var/lib/juju/storage/database/0 1.0GiB attached Successfully provisioned volume pvc-f1549b23-7f2d-44c2-8bbb-87834316a 715 prometheus-k8s/1 database/1 filesystem kubernetes /var/lib/juju/storage/database/0 1.0GiB attached Successfully provisioned volume pvc-d31094c3-3deb-46c0-bdf8-179fa04b1 371 juju exec --unit prometheus-k8s/1 -- close-port 3000 this unit is not the leader juju exec --unit prometheus-k8s/0 -- opened-ports 3000/tcp juju exec --unit prometheus-k8s/1 -- opened-ports 3000/tcp juju:PRIMARY> db.openedPorts.find().pretty() { "_id" : "d83ce064-96e9-4521-82f6-bae42cd69d53:a#prometheus-k8s", "model-uuid" : "d83ce064-96e9-4521-82f6-bae42cd69d53", "application-name" : "prometheus-k8s", "port-ranges" : { "" : [ { "fromport" : 3000, "toport" : 3000, "protocol" : "tcp" } ] }, "txn-revno" : 2 } juju upgrade-controller -c k1 --agent-version 3.1.1 best version: 3.1.1 started upgrade to 3.1.1 juju upgrade-model -m t1 best version: 3.1.1 started upgrade to 3.1.1 juju:PRIMARY> db.openedPorts.find().pretty() { "_id" : "d83ce064-96e9-4521-82f6-bae42cd69d53:a#prometheus-k8s", "model-uuid" : "d83ce064-96e9-4521-82f6-bae42cd69d53", "application-name" : "prometheus-k8s", "port-ranges" : { }, "txn-revno" : NumberLong(3), "unit-port-ranges" : { "prometheus-k8s/0" : { "" : [ { "fromport" : 3000, "toport" : 3000, "protocol" : "tcp" } ] }, "prometheus-k8s/1" : { "" : [ { "fromport" : 3000, "toport" : 3000, "protocol" : "tcp" } ] } } } juju exec --unit prometheus-k8s/0 -- opened-ports 3000/tcp juju exec --unit prometheus-k8s/1 -- opened-ports 3000/tcp juju exec --unit prometheus-k8s/1 -- close-port 3000 juju:PRIMARY> db.openedPorts.find().pretty() { "_id" : "3899fbb4-bc47-43d6-82af-bf35dc626ac2:a#prometheus-k8s", "model-uuid" : "3899fbb4-bc47-43d6-82af-bf35dc626ac2", "application-name" : "prometheus-k8s", "port-ranges" : { }, "txn-revno" : NumberLong(4), "unit-port-ranges" : { "prometheus-k8s/1" : { }, "prometheus-k8s/0" : { "" : [ { "fromport" : 3000, "toport" : 3000, "protocol" : "tcp" } ] } } } juju exec --unit prometheus-k8s/0 -- opened-ports 3000/tcp juju exec --unit prometheus-k8s/1 -- opened-ports ``` ## Documentation changes Now, sidecar and machine applications are same for open[/close]-port ## Bug reference https://bugs.launchpad.net/juju/+bug/2007334
2 parents ce6a255 + d79bab1 commit 7dfbd61

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2253
-670
lines changed

api/agent/uniter/uniter.go

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import (
77
"fmt"
88

99
"github.com/juju/charm/v10"
10+
"github.com/juju/collections/transform"
1011
"github.com/juju/errors"
1112
"github.com/juju/names/v4"
1213

1314
"github.com/juju/juju/api"
1415
"github.com/juju/juju/api/base"
1516
"github.com/juju/juju/api/common"
1617
apiwatcher "github.com/juju/juju/api/watcher"
18+
apiservererrors "github.com/juju/juju/apiserver/errors"
1719
"github.com/juju/juju/core/application"
1820
"github.com/juju/juju/core/life"
1921
"github.com/juju/juju/core/model"
@@ -380,23 +382,14 @@ func (st *State) Model() (*model.Model, error) {
380382
}, nil
381383
}
382384

383-
// OpenedMachinePortRangesByEndpoint returns all port ranges currently open on the given
384-
// machine, grouped by unit tag and application endpoint.
385-
func (st *State) OpenedMachinePortRangesByEndpoint(machineTag names.MachineTag) (map[names.UnitTag]network.GroupedPortRanges, error) {
386-
var results params.OpenMachinePortRangesByEndpointResults
387-
args := params.Entities{
388-
Entities: []params.Entity{{Tag: machineTag.String()}},
389-
}
390-
err := st.facade.FacadeCall("OpenedMachinePortRangesByEndpoint", args, &results)
391-
if err != nil {
392-
return nil, err
393-
}
385+
func processOpenPortRangesByEndpointResults(results params.OpenPortRangesByEndpointResults, tag names.Tag) (map[names.UnitTag]network.GroupedPortRanges, error) {
394386
if len(results.Results) != 1 {
395387
return nil, fmt.Errorf("expected 1 result, got %d", len(results.Results))
396388
}
397389
result := results.Results[0]
398390
if result.Error != nil {
399-
return nil, result.Error
391+
err := apiservererrors.RestoreError(result.Error)
392+
return nil, errors.Annotatef(err, "unable to fetch opened ports for %s", tag)
400393
}
401394

402395
portRangeMap := make(map[names.UnitTag]network.GroupedPortRanges)
@@ -406,24 +399,48 @@ func (st *State) OpenedMachinePortRangesByEndpoint(machineTag names.MachineTag)
406399
return nil, errors.Trace(err)
407400
}
408401
portRangeMap[unitTag] = make(network.GroupedPortRanges)
409-
410402
for _, group := range unitPortRanges {
411-
portList := make([]network.PortRange, len(group.PortRanges))
412-
for i, pr := range group.PortRanges {
413-
portList[i] = pr.NetworkPortRange()
414-
}
415-
portRangeMap[unitTag][group.Endpoint] = portList
403+
portRangeMap[unitTag][group.Endpoint] = transform.Slice(group.PortRanges, func(pr params.PortRange) network.PortRange {
404+
return pr.NetworkPortRange()
405+
})
416406
}
417407
}
418408
return portRangeMap, nil
419409
}
420410

411+
// OpenedMachinePortRangesByEndpoint returns all port ranges currently open on the given
412+
// machine, grouped by unit tag and application endpoint.
413+
func (st *State) OpenedMachinePortRangesByEndpoint(machineTag names.MachineTag) (map[names.UnitTag]network.GroupedPortRanges, error) {
414+
var results params.OpenPortRangesByEndpointResults
415+
args := params.Entities{
416+
Entities: []params.Entity{{Tag: machineTag.String()}},
417+
}
418+
err := st.facade.FacadeCall("OpenedMachinePortRangesByEndpoint", args, &results)
419+
if err != nil {
420+
return nil, err
421+
}
422+
return processOpenPortRangesByEndpointResults(results, machineTag)
423+
}
424+
425+
// OpenedPortRangesByEndpoint returns all port ranges currently opened grouped by unit tag and application endpoint.
426+
func (st *State) OpenedPortRangesByEndpoint() (map[names.UnitTag]network.GroupedPortRanges, error) {
427+
if st.BestAPIVersion() < 18 {
428+
// OpenedPortRangesByEndpoint() was introduced in UniterAPIV18.
429+
return nil, errors.NotImplementedf("OpenedPortRangesByEndpoint() (need V18+)")
430+
}
431+
var results params.OpenPortRangesByEndpointResults
432+
if err := st.facade.FacadeCall("OpenedPortRangesByEndpoint", nil, &results); err != nil {
433+
return nil, errors.Trace(err)
434+
}
435+
return processOpenPortRangesByEndpointResults(results, st.unitTag)
436+
}
437+
421438
// OpenedApplicationPortRangesByEndpoint returns all port ranges currently open for the given
422439
// application, grouped by application endpoint.
423440
func (st *State) OpenedApplicationPortRangesByEndpoint(appTag names.ApplicationTag) (network.GroupedPortRanges, error) {
424441
if st.BestAPIVersion() < 18 {
425442
// OpenedApplicationPortRangesByEndpoint() was introduced in UniterAPIV18.
426-
return nil, errors.NotImplementedf("OpenedApplicationPortRangesByEndpoint() (need V17+)")
443+
return nil, errors.NotImplementedf("OpenedApplicationPortRangesByEndpoint() (need V18+)")
427444
}
428445
arg := params.Entity{Tag: appTag.String()}
429446
var result params.ApplicationOpenedPortsResults
@@ -435,7 +452,8 @@ func (st *State) OpenedApplicationPortRangesByEndpoint(appTag names.ApplicationT
435452
}
436453
res := result.Results[0]
437454
if res.Error != nil {
438-
return nil, errors.Annotatef(res.Error, "unable to fetch opened ports for application %s", appTag)
455+
err := apiservererrors.RestoreError(res.Error)
456+
return nil, errors.Annotatef(err, "unable to fetch opened ports for %s", appTag)
439457
}
440458
out := make(network.GroupedPortRanges)
441459
for _, pgs := range res.ApplicationPortRanges {

api/agent/uniter/uniter_test.go

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,9 @@ func (s *uniterSuite) TestOpenedMachinePortRangesByEndpoint(c *gc.C) {
4444
c.Assert(objType, gc.Equals, "Uniter")
4545
c.Assert(request, gc.Equals, "OpenedMachinePortRangesByEndpoint")
4646
c.Assert(arg, gc.DeepEquals, params.Entities{Entities: []params.Entity{{Tag: "machine-42"}}})
47-
c.Assert(result, gc.FitsTypeOf, &params.OpenMachinePortRangesByEndpointResults{})
48-
*(result.(*params.OpenMachinePortRangesByEndpointResults)) = params.OpenMachinePortRangesByEndpointResults{
49-
Results: []params.OpenMachinePortRangesByEndpointResult{
47+
c.Assert(result, gc.FitsTypeOf, &params.OpenPortRangesByEndpointResults{})
48+
*(result.(*params.OpenPortRangesByEndpointResults)) = params.OpenPortRangesByEndpointResults{
49+
Results: []params.OpenPortRangesByEndpointResult{
5050
{
5151
UnitPortRanges: map[string][]params.OpenUnitPortRangesByEndpoint{
5252
"unit-mysql-0": {
@@ -87,6 +87,54 @@ func (s *uniterSuite) TestOpenedMachinePortRangesByEndpoint(c *gc.C) {
8787
})
8888
}
8989

90+
func (s *uniterSuite) TestOpenedPortRangesByEndpoint(c *gc.C) {
91+
apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
92+
c.Assert(objType, gc.Equals, "Uniter")
93+
c.Assert(request, gc.Equals, "OpenedPortRangesByEndpoint")
94+
c.Assert(arg, gc.IsNil)
95+
c.Assert(result, gc.FitsTypeOf, &params.OpenPortRangesByEndpointResults{})
96+
*(result.(*params.OpenPortRangesByEndpointResults)) = params.OpenPortRangesByEndpointResults{
97+
Results: []params.OpenPortRangesByEndpointResult{
98+
{
99+
UnitPortRanges: map[string][]params.OpenUnitPortRangesByEndpoint{
100+
"unit-mysql-0": {
101+
{
102+
Endpoint: "",
103+
PortRanges: []params.PortRange{{100, 200, "tcp"}},
104+
},
105+
{
106+
Endpoint: "server",
107+
PortRanges: []params.PortRange{{3306, 3306, "tcp"}},
108+
},
109+
},
110+
"unit-wordpress-0": {
111+
{
112+
Endpoint: "monitoring-port",
113+
PortRanges: []params.PortRange{{1337, 1337, "udp"}},
114+
},
115+
},
116+
},
117+
},
118+
},
119+
}
120+
return nil
121+
})
122+
caller := testing.BestVersionCaller{apiCaller, 18}
123+
client := uniter.NewState(caller, names.NewUnitTag("gitlab/0"))
124+
125+
result, err := client.OpenedPortRangesByEndpoint()
126+
c.Assert(err, jc.ErrorIsNil)
127+
c.Assert(result, jc.DeepEquals, map[names.UnitTag]network.GroupedPortRanges{
128+
names.NewUnitTag("mysql/0"): {
129+
"": []network.PortRange{network.MustParsePortRange("100-200/tcp")},
130+
"server": []network.PortRange{network.MustParsePortRange("3306/tcp")},
131+
},
132+
names.NewUnitTag("wordpress/0"): {
133+
"monitoring-port": []network.PortRange{network.MustParsePortRange("1337/udp")},
134+
},
135+
})
136+
}
137+
90138
func (s *uniterSuite) TestOpenedApplicationPortRangesByEndpoint(c *gc.C) {
91139
apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
92140
c.Assert(objType, gc.Equals, "Uniter")
@@ -126,12 +174,26 @@ func (s *uniterSuite) TestOpenedApplicationPortRangesByEndpointOldAPINotSupporte
126174
apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
127175
c.Assert(objType, gc.Equals, "Uniter")
128176
c.Assert(request, gc.Equals, "OpenedApplicationPortRangesByEndpoint")
129-
c.Assert(arg, gc.DeepEquals, params.Entities{Entities: []params.Entity{{Tag: "application-gitlab"}}})
177+
c.Assert(arg, gc.DeepEquals, params.Entities{Entities: []params.Entity{{Tag: "unit-gitlab-0"}}})
130178
return nil
131179
})
132180
caller := testing.BestVersionCaller{apiCaller, 17}
133181
client := uniter.NewState(caller, names.NewUnitTag("gitlab/0"))
134182

135183
_, err := client.OpenedApplicationPortRangesByEndpoint(names.NewApplicationTag("gitlab"))
136-
c.Assert(err, gc.ErrorMatches, `OpenedApplicationPortRangesByEndpoint\(\) \(need V17\+\) not implemented`)
184+
c.Assert(err, gc.ErrorMatches, `OpenedApplicationPortRangesByEndpoint\(\) \(need V18\+\) not implemented`)
185+
}
186+
187+
func (s *uniterSuite) TestOpenedPortRangesByEndpointOldAPINotSupported(c *gc.C) {
188+
apiCaller := testing.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
189+
c.Assert(objType, gc.Equals, "Uniter")
190+
c.Assert(request, gc.Equals, "OpenedPortRangesByEndpoint")
191+
c.Assert(arg, gc.DeepEquals, params.Entities{Entities: []params.Entity{{Tag: "unit-gitlab-0"}}})
192+
return nil
193+
})
194+
caller := testing.BestVersionCaller{apiCaller, 17}
195+
client := uniter.NewState(caller, names.NewUnitTag("gitlab/0"))
196+
197+
_, err := client.OpenedPortRangesByEndpoint()
198+
c.Assert(err, gc.ErrorMatches, `OpenedPortRangesByEndpoint\(\) \(need V18\+\) not implemented`)
137199
}

api/controller/caasfirewaller/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,13 @@ func (c *ClientSidecar) WatchOpenedPorts() (watcher.StringsWatcher, error) {
8787
return w, nil
8888
}
8989

90-
// GetApplicationOpenedPorts returns all the opened ports for each given application.
91-
func (c *ClientSidecar) GetApplicationOpenedPorts(appName string) (network.GroupedPortRanges, error) {
90+
// GetOpenedPorts returns all the opened ports for each given application.
91+
func (c *ClientSidecar) GetOpenedPorts(appName string) (network.GroupedPortRanges, error) {
9292
arg := params.Entity{
9393
Tag: names.NewApplicationTag(appName).String(),
9494
}
9595
var result params.ApplicationOpenedPortsResults
96-
if err := c.facade.FacadeCall("GetApplicationOpenedPorts", arg, &result); err != nil {
96+
if err := c.facade.FacadeCall("GetOpenedPorts", arg, &result); err != nil {
9797
return nil, errors.Trace(err)
9898
}
9999
if len(result.Results) != 1 {

api/controller/caasfirewaller/client_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ func (s *firewallerSidecarSuite) TestWatchOpenedPorts(c *gc.C) {
8787
c.Assert(err, gc.ErrorMatches, "FAIL")
8888
}
8989

90-
func (s *firewallerSidecarSuite) TestGetApplicationOpenedPorts(c *gc.C) {
90+
func (s *firewallerSidecarSuite) TestGetOpenedPorts(c *gc.C) {
9191
apiCaller := basetesting.APICallerFunc(func(objType string, version int, id, request string, arg, result interface{}) error {
9292
c.Check(objType, gc.Equals, s.objType)
9393
c.Check(version, gc.Equals, 0)
9494
c.Check(id, gc.Equals, "")
95-
c.Check(request, gc.Equals, "GetApplicationOpenedPorts")
95+
c.Check(request, gc.Equals, "GetOpenedPorts")
9696
c.Check(arg, jc.DeepEquals, params.Entity{Tag: "application-gitlab"})
9797
c.Assert(result, gc.FitsTypeOf, &params.ApplicationOpenedPortsResults{})
9898
*(result.(*params.ApplicationOpenedPortsResults)) = params.ApplicationOpenedPortsResults{
@@ -114,7 +114,7 @@ func (s *firewallerSidecarSuite) TestGetApplicationOpenedPorts(c *gc.C) {
114114
})
115115

116116
client := caasfirewaller.NewClientSidecar(apiCaller)
117-
result, err := client.GetApplicationOpenedPorts("gitlab")
117+
result, err := client.GetOpenedPorts("gitlab")
118118
c.Assert(err, jc.ErrorIsNil)
119119
c.Assert(result, jc.DeepEquals, network.GroupedPortRanges{
120120
"": []network.PortRange{

0 commit comments

Comments
 (0)