From d88bd5c7e7d30db4eed2352b53e2be71bdbf9dbd Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Tue, 22 Sep 2020 18:29:28 +0100 Subject: [PATCH 1/6] Add missing test for the upgrade model command This test was supposed to land together with commit d1b5f22524 but was unfortunately skipped. --- cmd/juju/commands/upgrademodel_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmd/juju/commands/upgrademodel_test.go b/cmd/juju/commands/upgrademodel_test.go index 8014757ebe0..bff6c451f30 100644 --- a/cmd/juju/commands/upgrademodel_test.go +++ b/cmd/juju/commands/upgrademodel_test.go @@ -915,6 +915,19 @@ func (s *UpgradeJujuSuite) TestUpgradeValidateModel(c *gc.C) { c.Assert(err, gc.ErrorMatches, `a message from the server about the problem`) } +func (s *UpgradeJujuSuite) TestUpgradeValidateModelNotImplementedNoError(c *gc.C) { + fakeAPI := NewFakeUpgradeJujuAPI(c, s.State) + + fakeAPI.setUpgradeErr = errors.NotImplementedf("") + + command := s.upgradeJujuCommand(nil, fakeAPI, fakeAPI, fakeAPI, fakeAPI) + err := cmdtesting.InitCommand(command, []string{}) + c.Assert(err, jc.ErrorIsNil) + + err = command.Run(cmdtesting.Context(c)) + c.Assert(err, jc.ErrorIsNil) +} + func (s *UpgradeJujuSuite) TestUpgradeInProgress(c *gc.C) { fakeAPI := NewFakeUpgradeJujuAPI(c, s.State) fakeAPI.setVersionErr = ¶ms.Error{ From 9c644198ebd47863795f37a65c9150fd5a46f3f1 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Thu, 17 Sep 2020 13:00:19 +0100 Subject: [PATCH 2/6] Bump bundlechanges and charm package versions The new version of bundlechanges includes exposed endpoints when diffing bundles and models. --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 5600cd6f107..d30635832fd 100644 --- a/go.mod +++ b/go.mod @@ -41,8 +41,8 @@ require ( github.com/joyent/gosdc v0.0.0-20140524000815-2f11feadd2d9 github.com/joyent/gosign v0.0.0-20140524000734-0da0d5f13420 github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a - github.com/juju/bundlechanges/v3 v3.0.0-20200909112830-2eb08291b192 - github.com/juju/charm/v8 v8.0.0-20200909140628-b1139b81a49c + github.com/juju/bundlechanges/v3 v3.0.0-20200922122015-fa9072606a43 + github.com/juju/charm/v8 v8.0.0-20200918105822-d7e8e94ba938 github.com/juju/charmrepo/v6 v6.0.0-20200817155725-120bd7a8b1ed github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c github.com/juju/cmd v0.0.0-20200108104440-8e43f3faa5c9 diff --git a/go.sum b/go.sum index 46a595634c5..0d899328768 100644 --- a/go.sum +++ b/go.sum @@ -385,16 +385,16 @@ github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/juju/bundlechanges v1.0.0 h1:MWHsdeas7iy5uJJlgqKCNmgUCr3aTgV4Vn+Sz5L3UJg= github.com/juju/bundlechanges v1.0.0/go.mod h1:nsBnRyayHbdHeduPzHgQVwbYhUz73aiRTjfJl5d86Uc= -github.com/juju/bundlechanges/v3 v3.0.0-20200909112830-2eb08291b192 h1:8Mq1glZyjPMVTa/Gm5/rhwTcRaCjlc3iRgwYWaz8RQU= -github.com/juju/bundlechanges/v3 v3.0.0-20200909112830-2eb08291b192/go.mod h1:NGfqo071vAdp2luMKdLBeUkj/FFd5D5grnXxhkxb00I= +github.com/juju/bundlechanges/v3 v3.0.0-20200922122015-fa9072606a43 h1:C3tYNYNe88H00gpj0Hag1qlegEzLDzXaDT6Y3QYSfWE= +github.com/juju/bundlechanges/v3 v3.0.0-20200922122015-fa9072606a43/go.mod h1:NGfqo071vAdp2luMKdLBeUkj/FFd5D5grnXxhkxb00I= github.com/juju/charm/v7 v7.0.0-20200424215011-2c5875af8596/go.mod h1:/Hb24f6NaHMuxV/XeKR9v1QY8qCc0NanWAXQuv6+Ob0= github.com/juju/charm/v7 v7.0.0-20200424224456-5fe646695e85 h1:YgEB2tnlAwVftOnPUKTN4i6NDYZy0ztR5l/HdUuHS2Y= github.com/juju/charm/v7 v7.0.0-20200424224456-5fe646695e85/go.mod h1:gcqIN/pHfzDCH6sBeZxmUfrNogknAPejOLS2KN0zY/0= github.com/juju/charm/v8 v8.0.0-20200817113526-2a88e9b46b47 h1:gZlV4PPG+B4iQVBpFalehMueLOrFVj/Qyl/M0rFAOC4= github.com/juju/charm/v8 v8.0.0-20200817113526-2a88e9b46b47/go.mod h1:N4PMPMcfLJ4jZaQ2NKfgRb56bcznVZBj5h/RygobR64= github.com/juju/charm/v8 v8.0.0-20200908083540-3ea1a8c7a8df/go.mod h1:N4PMPMcfLJ4jZaQ2NKfgRb56bcznVZBj5h/RygobR64= -github.com/juju/charm/v8 v8.0.0-20200909140628-b1139b81a49c h1:gP+KCiGlAGbmXTfg4NmNUnM+8/s0f4MK36LeZ6mxI6M= -github.com/juju/charm/v8 v8.0.0-20200909140628-b1139b81a49c/go.mod h1:N4PMPMcfLJ4jZaQ2NKfgRb56bcznVZBj5h/RygobR64= +github.com/juju/charm/v8 v8.0.0-20200918105822-d7e8e94ba938 h1:5I+IEeizHvI0nvN5vGuR4NOwAXtmy6azqIl5onEIXFA= +github.com/juju/charm/v8 v8.0.0-20200918105822-d7e8e94ba938/go.mod h1:N4PMPMcfLJ4jZaQ2NKfgRb56bcznVZBj5h/RygobR64= github.com/juju/charmrepo/v5 v5.0.0-20200424225329-cddcb4fdcd09/go.mod h1:KJGLR+Nx+PY2hw4EBNAjBWQacWlnxv1oVan1kJ9MlLM= github.com/juju/charmrepo/v6 v6.0.0-20200817155725-120bd7a8b1ed h1:1J537kQLlqU5xLhjVVM08f7uhlZ2DblbPLBWhrmn7x8= github.com/juju/charmrepo/v6 v6.0.0-20200817155725-120bd7a8b1ed/go.mod h1:kjlHVxArqqzYysU9tOom1tjaSHPlUzU6nzv8aFRAkOA= From f3b78ee215c1f74faba729162e30ad3c505e71c8 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Sep 2020 15:44:12 +0100 Subject: [PATCH 3/6] Add exposed-endpoint details in FullStatus payload. The new field is optional and not used by older controllers so we can avoid bumping the Client facade version. --- apiserver/facades/client/client/status.go | 76 +++++++++++++------ .../facades/client/client/status_test.go | 26 +++++++ apiserver/params/status.go | 31 ++++---- 3 files changed, 95 insertions(+), 38 deletions(-) diff --git a/apiserver/facades/client/client/status.go b/apiserver/facades/client/client/status.go index ab65fc6f13e..b194cdd8eef 100644 --- a/apiserver/facades/client/client/status.go +++ b/apiserver/facades/client/client/status.go @@ -186,6 +186,9 @@ func (c *Client) FullStatus(args params.StatusParams) (params.FullStatus, error) } context.providerType = cfg.Type() + if context.spaceInfos, err = c.api.stateAccessor.AllSpaceInfos(); err != nil { + return noStatus, errors.Annotate(err, "cannot obtain space information") + } if context.model, err = c.api.stateAccessor.Model(); err != nil { return noStatus, errors.Annotate(err, "could not fetch model") } @@ -193,7 +196,7 @@ func (c *Client) FullStatus(args params.StatusParams) (params.FullStatus, error) return noStatus, errors.Annotate(err, "could not load model status values") } if context.allAppsUnitsCharmBindings, err = - fetchAllApplicationsAndUnits(c.api.stateAccessor, context.model); err != nil { + fetchAllApplicationsAndUnits(c.api.stateAccessor, context.model, context.spaceInfos); err != nil { return noStatus, errors.Annotate(err, "could not fetch applications and units") } if context.consumerRemoteApplications, err = @@ -230,7 +233,7 @@ func (c *Client) FullStatus(args params.StatusParams) (params.FullStatus, error) } // These may be empty when machines have not finished deployment. if context.ipAddresses, context.spaces, context.linkLayerDevices, err = - fetchNetworkInterfaces(c.api.stateAccessor); err != nil { + fetchNetworkInterfaces(c.api.stateAccessor, context.spaceInfos); err != nil { return noStatus, errors.Annotate(err, "could not fetch IP addresses and link layer devices") } if context.relations, context.relationsById, err = fetchRelations(c.api.stateAccessor); err != nil { @@ -550,6 +553,9 @@ type statusContext struct { leaders map[string]string branches map[string]cache.Branch + // Information about all spaces. + spaceInfos network.SpaceInfos + primaryHAMachine *names.MachineTag } @@ -629,7 +635,7 @@ func fetchControllerNodes(st Backend) (map[string]state.ControllerNode, error) { // // All are required to determine a machine's network interfaces configuration, // so we want all or none. -func fetchNetworkInterfaces(st Backend) (map[string][]*state.Address, map[string]map[string]set.Strings, map[string][]*state.LinkLayerDevice, error) { +func fetchNetworkInterfaces(st Backend, spaceInfos network.SpaceInfos) (map[string][]*state.Address, map[string]map[string]set.Strings, map[string][]*state.LinkLayerDevice, error) { ipAddresses := make(map[string][]*state.Address) spacesPerMachine := make(map[string]map[string]set.Strings) subnets, err := st.AllSubnets() @@ -641,10 +647,6 @@ func fetchNetworkInterfaces(st Backend) (map[string][]*state.Address, map[string subnetsByCIDR[subnet.CIDR()] = subnet } - spaceInfos, err := st.AllSpaceInfos() - if err != nil { - return nil, nil, nil, err - } // For every machine, track what devices have addresses so we can filter linklayerdevices later devicesWithAddresses := make(map[string]set.Strings) ipAddrs, err := st.AllIPAddresses() @@ -714,10 +716,7 @@ func fetchNetworkInterfaces(st Backend) (map[string][]*state.Address, map[string // fetchAllApplicationsAndUnits returns a map from application name to application, // a map from application name to unit name to unit, and a map from base charm URL to latest URL. -func fetchAllApplicationsAndUnits( - st Backend, - model *state.Model, -) (applicationStatusInfo, error) { +func fetchAllApplicationsAndUnits(st Backend, model *state.Model, spaceInfos network.SpaceInfos) (applicationStatusInfo, error) { appMap := make(map[string]*state.Application) unitMap := make(map[string]map[string]*state.Unit) latestCharms := make(map[charm.URL]*state.Charm) @@ -742,11 +741,6 @@ func fetchAllApplicationsAndUnits( } } - allSpaceInfos, err := st.AllSpaceInfos() - if err != nil { - return applicationStatusInfo{}, errors.Trace(err) - } - endpointBindings, err := model.AllEndpointBindings() if err != nil { return applicationStatusInfo{}, err @@ -755,7 +749,7 @@ func fetchAllApplicationsAndUnits( for app, bindings := range endpointBindings { // If the only binding is the default, and it's set to the // default space, no need to print. - bindingMap, err := bindings.MapWithSpaceNames(allSpaceInfos) + bindingMap, err := bindings.MapWithSpaceNames(spaceInfos) if err != nil { return applicationStatusInfo{}, err } @@ -1174,13 +1168,19 @@ func (context *statusContext) processApplication(application *state.Application) charmProfileName = lxdprofile.Name(context.model.Name(), application.Name(), applicationCharm.Revision()) } + mappedExposedEndpoints, err := context.mapExposedEndpointsFromState(application.ExposedEndpoints()) + if err != nil { + return params.ApplicationStatus{Err: apiservererrors.ServerError(err)} + } + var processedStatus = params.ApplicationStatus{ - Charm: applicationCharm.URL().String(), - Series: application.Series(), - Exposed: application.IsExposed(), - Life: processLife(application), - CharmVersion: applicationCharm.Version(), - CharmProfile: charmProfileName, + Charm: applicationCharm.URL().String(), + Series: application.Series(), + Exposed: application.IsExposed(), + ExposedEndpoints: mappedExposedEndpoints, + Life: processLife(application), + CharmVersion: applicationCharm.Version(), + CharmProfile: charmProfileName, } if latestCharm, ok := context.allAppsUnitsCharmBindings.latestCharms[*applicationCharm.URL().WithRevision(-1)]; ok && latestCharm != nil { @@ -1273,6 +1273,36 @@ func (context *statusContext) processApplication(application *state.Application) return processedStatus } +func (context *statusContext) mapExposedEndpointsFromState(exposedEndpoints map[string]state.ExposedEndpoint) (map[string]params.ExposedEndpoint, error) { + if len(exposedEndpoints) == 0 { + return nil, nil + } + + res := make(map[string]params.ExposedEndpoint, len(exposedEndpoints)) + for endpointName, exposeDetails := range exposedEndpoints { + mappedParam := params.ExposedEndpoint{ + ExposeToCIDRs: exposeDetails.ExposeToCIDRs, + } + + if len(exposeDetails.ExposeToSpaceIDs) != 0 { + spaceNames := make([]string, len(exposeDetails.ExposeToSpaceIDs)) + for i, spaceID := range exposeDetails.ExposeToSpaceIDs { + sp := context.spaceInfos.GetByID(spaceID) + if sp == nil { + return nil, errors.NotFoundf("space with ID %q", spaceID) + } + + spaceNames[i] = string(sp.Name) + } + mappedParam.ExposeToSpaces = spaceNames + } + + res[endpointName] = mappedParam + } + + return res, nil +} + func (context *statusContext) processRemoteApplications() map[string]params.RemoteApplicationStatus { applicationsMap := make(map[string]params.RemoteApplicationStatus) for _, app := range context.consumerRemoteApplications { diff --git a/apiserver/facades/client/client/status_test.go b/apiserver/facades/client/client/status_test.go index 86eb89cab9d..eb9f571070b 100644 --- a/apiserver/facades/client/client/status_test.go +++ b/apiserver/facades/client/client/status_test.go @@ -425,6 +425,32 @@ func (s *statusUnitTestSuite) TestMeterStatusWithCredentials(c *gc.C) { } } +func (s *statusUnitTestSuite) TestApplicationWithExposedEndpoints(c *gc.C) { + meteredCharm := s.Factory.MakeCharm(c, &factory.CharmParams{Name: "metered", URL: "cs:quantal/metered"}) + service := s.Factory.MakeApplication(c, &factory.ApplicationParams{Charm: meteredCharm}) + err := service.MergeExposeSettings(map[string]state.ExposedEndpoint{ + "": { + ExposeToSpaceIDs: []string{network.AlphaSpaceId}, + ExposeToCIDRs: []string{"10.0.0.0/24", "192.168.0.0/24"}, + }, + }) + c.Assert(err, jc.ErrorIsNil) + + client := s.APIState.Client() + status, err := client.Status(nil) + c.Assert(err, jc.ErrorIsNil) + c.Assert(status, gc.NotNil) + serviceStatus, ok := status.Applications[service.Name()] + c.Assert(ok, gc.Equals, true) + + c.Assert(serviceStatus.ExposedEndpoints, gc.DeepEquals, map[string]params.ExposedEndpoint{ + "": { + ExposeToSpaces: []string{network.AlphaSpaceName}, + ExposeToCIDRs: []string{"10.0.0.0/24", "192.168.0.0/24"}, + }, + }) +} + func addUnitWithVersion(c *gc.C, application *state.Application, version string) *state.Unit { unit, err := application.AddUnit(state.AddUnitParams{}) c.Assert(err, jc.ErrorIsNil) diff --git a/apiserver/params/status.go b/apiserver/params/status.go index 53c795c9831..b8998a7b59d 100644 --- a/apiserver/params/status.go +++ b/apiserver/params/status.go @@ -140,21 +140,22 @@ type LXDProfile struct { // ApplicationStatus holds status info about an application. type ApplicationStatus struct { - Err *Error `json:"err,omitempty"` - Charm string `json:"charm"` - Series string `json:"series"` - Exposed bool `json:"exposed"` - Life life.Value `json:"life"` - Relations map[string][]string `json:"relations"` - CanUpgradeTo string `json:"can-upgrade-to"` - SubordinateTo []string `json:"subordinate-to"` - Units map[string]UnitStatus `json:"units"` - MeterStatuses map[string]MeterStatus `json:"meter-statuses"` - Status DetailedStatus `json:"status"` - WorkloadVersion string `json:"workload-version"` - CharmVersion string `json:"charm-version"` - CharmProfile string `json:"charm-profile"` - EndpointBindings map[string]string `json:"endpoint-bindings"` + Err *Error `json:"err,omitempty"` + Charm string `json:"charm"` + Series string `json:"series"` + Exposed bool `json:"exposed"` + ExposedEndpoints map[string]ExposedEndpoint `json:"exposed-endpoints,omitempty"` + Life life.Value `json:"life"` + Relations map[string][]string `json:"relations"` + CanUpgradeTo string `json:"can-upgrade-to"` + SubordinateTo []string `json:"subordinate-to"` + Units map[string]UnitStatus `json:"units"` + MeterStatuses map[string]MeterStatus `json:"meter-statuses"` + Status DetailedStatus `json:"status"` + WorkloadVersion string `json:"workload-version"` + CharmVersion string `json:"charm-version"` + CharmProfile string `json:"charm-profile"` + EndpointBindings map[string]string `json:"endpoint-bindings"` // The following are for CAAS models. Scale int `json:"int,omitempty"` From c459b3afb197917d59c28abf2b8126279147c500 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Sep 2020 15:49:57 +0100 Subject: [PATCH 4/6] Include exposed endpoints in diff-bundle output --- cmd/juju/application/bundle/bundle.go | 9 ++ cmd/juju/application/bundle/bundle_test.go | 59 +++++++++ cmd/juju/application/bundlediff_test.go | 146 +++++++++++++++++++++ 3 files changed, 214 insertions(+) diff --git a/cmd/juju/application/bundle/bundle.go b/cmd/juju/application/bundle/bundle.go index e342433251c..3216bb1eb99 100644 --- a/cmd/juju/application/bundle/bundle.go +++ b/cmd/juju/application/bundle/bundle.go @@ -66,6 +66,15 @@ func BuildModelRepresentation( Series: appStatus.Series, SubordinateTo: appStatus.SubordinateTo, } + if len(appStatus.ExposedEndpoints) != 0 { + app.ExposedEndpoints = make(map[string]bundlechanges.ExposedEndpoint) + for endpoint, exposeDetails := range appStatus.ExposedEndpoints { + app.ExposedEndpoints[endpoint] = bundlechanges.ExposedEndpoint{ + ExposeToSpaces: exposeDetails.ExposeToSpaces, + ExposeToCIDRs: exposeDetails.ExposeToCIDRs, + } + } + } for unitName, unit := range appStatus.Units { app.Units = append(app.Units, bundlechanges.Unit{ Name: unitName, diff --git a/cmd/juju/application/bundle/bundle_test.go b/cmd/juju/application/bundle/bundle_test.go index 462c287ba27..04093c8a96d 100644 --- a/cmd/juju/application/bundle/bundle_test.go +++ b/cmd/juju/application/bundle/bundle_test.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/golang/mock/gomock" + "github.com/juju/bundlechanges/v3" "github.com/juju/charm/v8" jc "github.com/juju/testing/checkers" gc "gopkg.in/check.v1" @@ -253,6 +254,64 @@ func (s *composeAndVerifyRepSuite) setupOverlayFile(c *gc.C) { jc.ErrorIsNil) } +func (s *buildModelRepSuite) TestBuildModelRepresentationApplicationsWithExposedEndpoints(c *gc.C) { + defer s.setupMocks(c).Finish() + s.expectGetAnnotations(c, []string{"machine-0", "application-wordpress"}) + s.expectGetConstraintsWordpress() + s.expectEmptySequences() + + s.modelExtractor.EXPECT().GetConfig(model.GenerationMaster, "wordpress").Return(nil, nil) + + status := ¶ms.FullStatus{ + Model: params.ModelStatusInfo{ + Name: "default", + }, + Machines: map[string]params.MachineStatus{ + "0": {Series: "bionic"}, + }, + Applications: map[string]params.ApplicationStatus{ + "wordpress": { + Series: "bionic", + Life: life.Alive, + Units: map[string]params.UnitStatus{ + "0": {Machine: "0"}, + }, + ExposedEndpoints: map[string]params.ExposedEndpoint{ + "": { + ExposeToCIDRs: []string{"10.0.0.0/24"}, + }, + "website": { + ExposeToSpaces: []string{"inner", "outer"}, + ExposeToCIDRs: []string{"192.168.0.0/24"}, + }, + }, + }, + }, + } + machines := map[string]string{} + + obtainedModel, err := BuildModelRepresentation(status, s.modelExtractor, false, machines) + c.Assert(err, jc.ErrorIsNil) + c.Assert(obtainedModel.Applications, gc.HasLen, 1) + obtainedWordpress, ok := obtainedModel.Applications["wordpress"] + c.Assert(ok, jc.IsTrue) + + c.Assert(obtainedWordpress.ExposedEndpoints, gc.DeepEquals, map[string]bundlechanges.ExposedEndpoint{ + "": { + ExposeToCIDRs: []string{"10.0.0.0/24"}, + }, + "website": { + ExposeToSpaces: []string{"inner", "outer"}, + ExposeToCIDRs: []string{"192.168.0.0/24"}, + }, + }) + + c.Assert(obtainedModel.Machines, gc.HasLen, 1) + c.Assert(obtainedModel.Relations, gc.HasLen, 0) + c.Assert(obtainedModel.Sequence, gc.HasLen, 0) + c.Assert(obtainedModel.MachineMap, gc.HasLen, 0) +} + func (s *composeAndVerifyRepSuite) setupMocks(c *gc.C) *gomock.Controller { ctrl := gomock.NewController(c) s.bundleDataSource = mocks.NewMockBundleDataSource(ctrl) diff --git a/cmd/juju/application/bundlediff_test.go b/cmd/juju/application/bundlediff_test.go index 7eb532e84dd..bc685722b9b 100644 --- a/cmd/juju/application/bundlediff_test.go +++ b/cmd/juju/application/bundlediff_test.go @@ -290,6 +290,115 @@ relations: c.Assert(strings.Contains(cmdtesting.Stdout(ctx), exp[1:]), jc.IsTrue) } +func (s *diffSuite) TestExposedEndpoints(c *gc.C) { + specs := []struct { + descr string + modelExposedEndpoints map[string]params.ExposedEndpoint + bundle string + expDiff string + }{ + { + descr: "2.8-compatible bundle with expose:true", + modelExposedEndpoints: map[string]params.ExposedEndpoint{ + "": { + ExposeToSpaces: []string{"alpha"}, + ExposeToCIDRs: []string{"10.0.0.0/24"}, + }, + }, + bundle: ` +applications: + prometheus: + charm: 'cs:prometheus2-7' + num_units: 1 + series: xenial + expose: true + to: + - 0 +machines: + '0': + series: xenial +`[1:], + expDiff: ` +applications: + prometheus: + exposed_endpoints: + "": + bundle: + expose_to_cidrs: + - 0.0.0.0/0 + - ::/0 + model: + expose_to_spaces: + - alpha + expose_to_cidrs: + - 10.0.0.0/24 +`[1:], + }, + { + descr: "2.9-compatible bundle with expose settings in overlay section", + modelExposedEndpoints: map[string]params.ExposedEndpoint{ + "website": { + ExposeToSpaces: []string{"alpha"}, + ExposeToCIDRs: []string{"10.0.0.0/24"}, + }, + }, + bundle: ` +applications: + prometheus: + charm: 'cs:prometheus2-7' + num_units: 1 + series: xenial + to: + - 0 +machines: + '0': + series: xenial +--- +applications: + prometheus: + exposed-endpoints: + "": + expose-to-cidrs: + - 0.0.0.0/0 + website: + expose-to-cidrs: + - 40.0.0.0/24 +`[1:], + expDiff: ` +applications: + prometheus: + exposed_endpoints: + "": + bundle: + expose_to_cidrs: + - 0.0.0.0/0 + model: null + website: + bundle: + expose_to_cidrs: + - 40.0.0.0/24 + model: + expose_to_spaces: + - alpha + expose_to_cidrs: + - 10.0.0.0/24 +`[1:], + }, + } + + for i, spec := range specs { + c.Logf("test %d: %s", i, spec.descr) + + s.apiRoot = &mockAPIRoot{responses: makeAPIResponsesWithExposedEndpoints(spec.modelExposedEndpoints)} + + ctx, err := s.runDiffBundle(c, s.writeLocalBundle(c, spec.bundle)) + c.Assert(err, jc.ErrorIsNil) + + c.Log(cmdtesting.Stdout(ctx)) + c.Assert(cmdtesting.Stdout(ctx), gc.Equals, spec.expDiff) + } +} + func (s *diffSuite) writeLocalBundle(c *gc.C, content string) string { return s.writeFile(c, "bundle.yaml", content) } @@ -375,6 +484,43 @@ func makeAPIResponsesWithRelations(relations []params.RelationStatus) map[string } } +func makeAPIResponsesWithExposedEndpoints(exposedEndpoints map[string]params.ExposedEndpoint) map[string]interface{} { + return map[string]interface{}{ + "ModelConfig.ModelGet": params.ModelConfigResults{ + Config: map[string]params.ConfigValue{ + "uuid": {Value: testing.ModelTag.Id()}, + "type": {Value: "iaas"}, + "name": {Value: "horse"}, + "default-series": {Value: "xenial"}, + }, + }, + "Client.FullStatus": params.FullStatus{ + Applications: map[string]params.ApplicationStatus{ + "prometheus": { + Charm: "cs:prometheus2-7", + Series: "xenial", + Life: "alive", + Units: map[string]params.UnitStatus{ + "prometheus/0": {Machine: "0"}, + }, + ExposedEndpoints: exposedEndpoints, + }, + }, + Machines: map[string]params.MachineStatus{ + "0": {Series: "xenial"}, + }, + }, + "Annotations.Get": params.AnnotationsGetResults{ + Results: []params.AnnotationsGetResult{{ + EntityTag: "application-prometheus", + }}, + }, + "ModelConfig.Sequences": params.ModelSequencesResult{}, + "Application.CharmConfig": params.ApplicationGetConfigResults{}, + "Application.GetConstraints": params.ApplicationGetConstraintsResults{}, + } +} + type mockCharmStore struct { stub jujutesting.Stub url *charm.URL From 8e0526462b69a9ff16c51489819e775aaec81e0f Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Sep 2020 15:56:12 +0100 Subject: [PATCH 5/6] Regenerate facade schema --- apiserver/facades/schema.json | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apiserver/facades/schema.json b/apiserver/facades/schema.json index a92ac572141..0f320a348f2 100644 --- a/apiserver/facades/schema.json +++ b/apiserver/facades/schema.json @@ -11475,6 +11475,14 @@ "exposed": { "type": "boolean" }, + "exposed-endpoints": { + "type": "object", + "patternProperties": { + ".*": { + "$ref": "#/definitions/ExposedEndpoint" + } + } + }, "int": { "type": "integer" }, @@ -11929,6 +11937,24 @@ "results" ] }, + "ExposedEndpoint": { + "type": "object", + "properties": { + "expose-to-cidrs": { + "type": "array", + "items": { + "type": "string" + } + }, + "expose-to-spaces": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, "FindToolsParams": { "type": "object", "properties": { From 64037dfe18d731ff5be54f6e643fd103d3c4f9a0 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Sep 2020 16:42:56 +0100 Subject: [PATCH 6/6] Fix expected expose change output in tests to include ::/0 --- cmd/juju/application/deployer/bundlehandler_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/juju/application/deployer/bundlehandler_test.go b/cmd/juju/application/deployer/bundlehandler_test.go index 4a78cba437c..3119d30e636 100644 --- a/cmd/juju/application/deployer/bundlehandler_test.go +++ b/cmd/juju/application/deployer/bundlehandler_test.go @@ -693,7 +693,7 @@ func (s *BundleDeployCharmStoreSuite) TestDeployBundleExpose(c *gc.C) { "Executing changes:\n"+ "- upload charm cs:wordpress-47\n"+ "- deploy application wordpress using cs:wordpress-47\n"+ - "- expose all endpoints of wordpress and allow access from CIDR 0.0.0.0/0\n"+ + "- expose all endpoints of wordpress and allow access from CIDRs 0.0.0.0/0 and ::/0\n"+ "- add unit wordpress/0 to new machine 0\n"+ "Deploy of bundle completed.\n") }