github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/firewaller/firewaller_unit_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package firewaller_test
     5  
     6  import (
     7  	"github.com/juju/names/v5"
     8  	jc "github.com/juju/testing/checkers"
     9  	"go.uber.org/mock/gomock"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	apitesting "github.com/juju/juju/api/testing"
    13  	"github.com/juju/juju/apiserver/common"
    14  	"github.com/juju/juju/apiserver/facades/controller/firewaller"
    15  	"github.com/juju/juju/apiserver/facades/controller/firewaller/mocks"
    16  	apiservertesting "github.com/juju/juju/apiserver/testing"
    17  	"github.com/juju/juju/controller"
    18  	"github.com/juju/juju/core/network"
    19  	"github.com/juju/juju/core/status"
    20  	"github.com/juju/juju/environs/config"
    21  	"github.com/juju/juju/rpc/params"
    22  	"github.com/juju/juju/state"
    23  	coretesting "github.com/juju/juju/testing"
    24  )
    25  
    26  var _ = gc.Suite(&RemoteFirewallerSuite{})
    27  
    28  type RemoteFirewallerSuite struct {
    29  	coretesting.BaseSuite
    30  
    31  	resources  *common.Resources
    32  	authorizer *apiservertesting.FakeAuthorizer
    33  	st         *mocks.MockState
    34  	cc         *mocks.MockControllerConfigAPI
    35  	api        *firewaller.FirewallerAPI
    36  }
    37  
    38  func (s *RemoteFirewallerSuite) SetUpTest(c *gc.C) {
    39  	s.BaseSuite.SetUpTest(c)
    40  
    41  	s.resources = common.NewResources()
    42  	s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() })
    43  
    44  	s.authorizer = &apiservertesting.FakeAuthorizer{
    45  		Tag:        names.NewMachineTag("0"),
    46  		Controller: true,
    47  	}
    48  }
    49  
    50  func (s *RemoteFirewallerSuite) setup(c *gc.C) *gomock.Controller {
    51  	ctrl := gomock.NewController(c)
    52  
    53  	s.st = mocks.NewMockState(ctrl)
    54  	s.cc = mocks.NewMockControllerConfigAPI(ctrl)
    55  	api, err := firewaller.NewStateFirewallerAPI(s.st, s.resources, s.authorizer, &mockCloudSpecAPI{}, s.cc)
    56  	c.Assert(err, jc.ErrorIsNil)
    57  	s.api = api
    58  	return ctrl
    59  }
    60  
    61  func (s *RemoteFirewallerSuite) TestWatchIngressAddressesForRelations(c *gc.C) {
    62  	defer s.setup(c).Finish()
    63  
    64  	db2Relation := newMockRelation(123)
    65  	s.st.EXPECT().ModelUUID().Return(coretesting.ModelTag.Id()).AnyTimes()
    66  	s.st.EXPECT().KeyRelation("remote-db2:db django:db").Return(db2Relation, nil)
    67  
    68  	result, err := s.api.WatchIngressAddressesForRelations(
    69  		params.Entities{Entities: []params.Entity{{
    70  			Tag: names.NewRelationTag("remote-db2:db django:db").String(),
    71  		}}},
    72  	)
    73  
    74  	c.Assert(err, jc.ErrorIsNil)
    75  	c.Assert(result.Results, gc.HasLen, 1)
    76  	c.Assert(result.Results[0].Changes, jc.SameContents, []string{"1.2.3.4/32"})
    77  	c.Assert(result.Results[0].Error, gc.IsNil)
    78  	c.Assert(result.Results[0].StringsWatcherId, gc.Equals, "1")
    79  
    80  	resource := s.resources.Get("1")
    81  	c.Assert(resource, gc.NotNil)
    82  	c.Assert(resource, gc.Implements, new(state.StringsWatcher))
    83  }
    84  
    85  func (s *RemoteFirewallerSuite) TestMacaroonForRelations(c *gc.C) {
    86  	defer s.setup(c).Finish()
    87  
    88  	mac, err := apitesting.NewMacaroon("apimac")
    89  	c.Assert(err, jc.ErrorIsNil)
    90  	entity := names.NewRelationTag("mysql:db wordpress:db")
    91  	s.st.EXPECT().GetMacaroon(entity).Return(mac, nil)
    92  
    93  	result, err := s.api.MacaroonForRelations(
    94  		params.Entities{Entities: []params.Entity{{
    95  			Tag: entity.String(),
    96  		}}},
    97  	)
    98  
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	c.Assert(result.Results, gc.HasLen, 1)
   101  	c.Assert(result.Results[0].Error, gc.IsNil)
   102  	c.Assert(result.Results[0].Result, jc.DeepEquals, mac)
   103  }
   104  
   105  func (s *RemoteFirewallerSuite) TestSetRelationStatus(c *gc.C) {
   106  	defer s.setup(c).Finish()
   107  
   108  	db2Relation := newMockRelation(123)
   109  	entity := names.NewRelationTag("remote-db2:db django:db")
   110  	s.st.EXPECT().ModelUUID().Return(coretesting.ModelTag.Id()).AnyTimes()
   111  	s.st.EXPECT().KeyRelation("remote-db2:db django:db").Return(db2Relation, nil)
   112  
   113  	result, err := s.api.SetRelationsStatus(
   114  		params.SetStatus{Entities: []params.EntityStatusArgs{{
   115  			Tag:    entity.String(),
   116  			Status: "suspended",
   117  			Info:   "a message",
   118  		}}})
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	c.Assert(result.Results, gc.HasLen, 1)
   121  	c.Assert(result.Results[0].Error, gc.IsNil)
   122  	c.Assert(db2Relation.status, jc.DeepEquals, status.StatusInfo{Status: status.Suspended, Message: "a message"})
   123  }
   124  
   125  var _ = gc.Suite(&FirewallerSuite{})
   126  
   127  type FirewallerSuite struct {
   128  	coretesting.BaseSuite
   129  
   130  	resources  *common.Resources
   131  	authorizer *apiservertesting.FakeAuthorizer
   132  
   133  	st  *mocks.MockState
   134  	cc  *mocks.MockControllerConfigAPI
   135  	api *firewaller.FirewallerAPI
   136  }
   137  
   138  func (s *FirewallerSuite) SetUpTest(c *gc.C) {
   139  	s.BaseSuite.SetUpTest(c)
   140  
   141  	s.resources = common.NewResources()
   142  	s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() })
   143  
   144  	s.authorizer = &apiservertesting.FakeAuthorizer{
   145  		Tag:        names.NewMachineTag("0"),
   146  		Controller: true,
   147  	}
   148  }
   149  
   150  func (s *FirewallerSuite) setup(c *gc.C) *gomock.Controller {
   151  	ctrl := gomock.NewController(c)
   152  
   153  	s.st = mocks.NewMockState(ctrl)
   154  	s.cc = mocks.NewMockControllerConfigAPI(ctrl)
   155  	api, err := firewaller.NewStateFirewallerAPI(s.st, s.resources, s.authorizer, &mockCloudSpecAPI{}, s.cc)
   156  	c.Assert(err, jc.ErrorIsNil)
   157  	s.api = api
   158  	return ctrl
   159  }
   160  
   161  func (s *FirewallerSuite) TestModelFirewallRules(c *gc.C) {
   162  	defer s.setup(c).Finish()
   163  
   164  	modelAttrs := coretesting.FakeConfig().Merge(map[string]interface{}{
   165  		config.SSHAllowKey: "192.168.0.0/24,192.168.1.0/24",
   166  	})
   167  	s.st.EXPECT().ModelConfig().Return(config.New(config.UseDefaults, modelAttrs))
   168  	s.st.EXPECT().ControllerConfig().Return(controller.NewConfig(coretesting.ControllerTag.Id(), coretesting.CACert, map[string]interface{}{}))
   169  	s.st.EXPECT().IsController().Return(false)
   170  
   171  	rules, err := s.api.ModelFirewallRules()
   172  
   173  	c.Assert(err, jc.ErrorIsNil)
   174  	c.Assert(rules, gc.DeepEquals, params.IngressRulesResult{Rules: []params.IngressRule{{
   175  		PortRange:   params.FromNetworkPortRange(network.MustParsePortRange("22")),
   176  		SourceCIDRs: []string{"192.168.0.0/24", "192.168.1.0/24"},
   177  	}}})
   178  }
   179  
   180  func (s *FirewallerSuite) TestModelFirewallRulesController(c *gc.C) {
   181  	defer s.setup(c).Finish()
   182  
   183  	modelAttrs := coretesting.FakeConfig().Merge(map[string]interface{}{
   184  		config.SSHAllowKey: "192.168.0.0/24,192.168.1.0/24",
   185  	})
   186  	s.st.EXPECT().ModelConfig().Return(config.New(config.UseDefaults, modelAttrs))
   187  
   188  	ctrlAttrs := map[string]interface{}{
   189  		controller.APIPort:            17777,
   190  		controller.AutocertDNSNameKey: "example.com",
   191  	}
   192  	s.st.EXPECT().ControllerConfig().Return(controller.NewConfig(coretesting.ControllerTag.Id(), coretesting.CACert, ctrlAttrs))
   193  	s.st.EXPECT().IsController().Return(true)
   194  
   195  	rules, err := s.api.ModelFirewallRules()
   196  
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	c.Assert(rules, gc.DeepEquals, params.IngressRulesResult{Rules: []params.IngressRule{{
   199  		PortRange:   params.FromNetworkPortRange(network.MustParsePortRange("22")),
   200  		SourceCIDRs: []string{"192.168.0.0/24", "192.168.1.0/24"},
   201  	}, {
   202  		PortRange:   params.FromNetworkPortRange(network.MustParsePortRange("17777")),
   203  		SourceCIDRs: []string{"0.0.0.0/0", "::/0"},
   204  	}, {
   205  		PortRange:   params.FromNetworkPortRange(network.MustParsePortRange("80")),
   206  		SourceCIDRs: []string{"0.0.0.0/0", "::/0"},
   207  	}}})
   208  }
   209  
   210  func (s *FirewallerSuite) TestWatchModelFirewallRules(c *gc.C) {
   211  	ctrl := s.setup(c)
   212  	defer ctrl.Finish()
   213  
   214  	ch := make(chan struct{}, 1)
   215  	// initial event
   216  	ch <- struct{}{}
   217  	w := mocks.NewMockNotifyWatcher(ctrl)
   218  	w.EXPECT().Changes().Return(ch).MinTimes(1)
   219  	w.EXPECT().Wait().AnyTimes()
   220  	w.EXPECT().Kill().AnyTimes()
   221  
   222  	s.st.EXPECT().WatchForModelConfigChanges().Return(w)
   223  	s.st.EXPECT().ModelConfig().Return(config.New(config.UseDefaults, coretesting.FakeConfig()))
   224  
   225  	result, err := s.api.WatchModelFirewallRules()
   226  	c.Assert(err, jc.ErrorIsNil)
   227  	c.Assert(result.Error, gc.IsNil)
   228  	c.Assert(result.NotifyWatcherId, gc.Equals, "1")
   229  
   230  	resource := s.resources.Get("1")
   231  	c.Assert(resource, gc.NotNil)
   232  	c.Assert(resource, gc.Implements, new(state.NotifyWatcher))
   233  }
   234  
   235  func (s *FirewallerSuite) TestOpenedMachinePortRanges(c *gc.C) {
   236  	defer s.setup(c).Finish()
   237  
   238  	// Set up our mocks
   239  	mockMachine := newMockMachine("0")
   240  	mockMachine.openedPortRanges = newMockMachinePortRanges(
   241  		newMockUnitPortRanges(
   242  			"wordpress/0",
   243  			network.GroupedPortRanges{
   244  				"": []network.PortRange{
   245  					network.MustParsePortRange("80/tcp"),
   246  				},
   247  			},
   248  		),
   249  		newMockUnitPortRanges(
   250  			"mysql/0",
   251  			network.GroupedPortRanges{
   252  				"foo": []network.PortRange{
   253  					network.MustParsePortRange("3306/tcp"),
   254  				},
   255  			},
   256  		),
   257  	)
   258  	spaceInfos := network.SpaceInfos{
   259  		{ID: network.AlphaSpaceId, Name: "alpha", Subnets: []network.SubnetInfo{
   260  			{ID: "11", CIDR: "10.0.0.0/24"},
   261  			{ID: "12", CIDR: "10.0.1.0/24"},
   262  		}},
   263  		{ID: "42", Name: "questions-about-the-universe", Subnets: []network.SubnetInfo{
   264  			{ID: "13", CIDR: "192.168.0.0/24"},
   265  			{ID: "14", CIDR: "192.168.1.0/24"},
   266  		}},
   267  	}
   268  	applicationEndpointBindings := map[string]map[string]string{
   269  		"mysql": {
   270  			"":    network.AlphaSpaceId,
   271  			"foo": "42",
   272  		},
   273  		"wordpress": {
   274  			"":           network.AlphaSpaceId,
   275  			"monitoring": network.AlphaSpaceId,
   276  			"web":        "42",
   277  		},
   278  	}
   279  	s.st.EXPECT().Machine("0").Return(mockMachine, nil)
   280  	s.st.EXPECT().SpaceInfos().Return(spaceInfos, nil)
   281  	s.st.EXPECT().AllEndpointBindings().Return(applicationEndpointBindings, nil)
   282  
   283  	// Test call output
   284  	req := params.Entities{
   285  		Entities: []params.Entity{
   286  			{Tag: names.NewMachineTag("0").String()},
   287  		},
   288  	}
   289  	res, err := s.api.OpenedMachinePortRanges(req)
   290  	c.Assert(err, jc.ErrorIsNil)
   291  	c.Assert(res.Results, gc.HasLen, 1)
   292  
   293  	c.Assert(res.Results[0].Error, gc.IsNil)
   294  	c.Assert(res.Results[0].UnitPortRanges, gc.DeepEquals, map[string][]params.OpenUnitPortRanges{
   295  		"unit-wordpress-0": {
   296  			{
   297  				Endpoint:    "",
   298  				SubnetCIDRs: []string{"10.0.0.0/24", "10.0.1.0/24", "192.168.0.0/24", "192.168.1.0/24"},
   299  				PortRanges: []params.PortRange{
   300  					params.FromNetworkPortRange(network.MustParsePortRange("80/tcp")),
   301  				},
   302  			},
   303  		},
   304  		"unit-mysql-0": {
   305  			{
   306  				Endpoint:    "foo",
   307  				SubnetCIDRs: []string{"192.168.0.0/24", "192.168.1.0/24"},
   308  				PortRanges: []params.PortRange{
   309  					params.FromNetworkPortRange(network.MustParsePortRange("3306/tcp")),
   310  				},
   311  			},
   312  		},
   313  	})
   314  }
   315  
   316  func (s *FirewallerSuite) TestAllSpaceInfos(c *gc.C) {
   317  	defer s.setup(c).Finish()
   318  
   319  	// Set up our mocks
   320  	spaceInfos := network.SpaceInfos{
   321  		{
   322  			ID:         "42",
   323  			Name:       "questions-about-the-universe",
   324  			ProviderId: "provider-id-2",
   325  			Subnets: []network.SubnetInfo{
   326  				{
   327  					ID:                "13",
   328  					CIDR:              "1.168.1.0/24",
   329  					ProviderId:        "provider-subnet-id-1",
   330  					ProviderSpaceId:   "provider-space-id-1",
   331  					ProviderNetworkId: "provider-network-id-1",
   332  					VLANTag:           42,
   333  					AvailabilityZones: []string{"az1", "az2"},
   334  					SpaceID:           "42",
   335  					SpaceName:         "questions-about-the-universe",
   336  					FanInfo: &network.FanCIDRs{
   337  						FanLocalUnderlay: "192.168.0.0/16",
   338  						FanOverlay:       "1.0.0.0/8",
   339  					},
   340  					IsPublic: true,
   341  				},
   342  			}},
   343  		{ID: "99", Name: "special", Subnets: []network.SubnetInfo{
   344  			{ID: "999", CIDR: "192.168.2.0/24"},
   345  		}},
   346  	}
   347  	s.st.EXPECT().SpaceInfos().Return(spaceInfos, nil)
   348  
   349  	// Test call output
   350  	req := params.SpaceInfosParams{
   351  		FilterBySpaceIDs: []string{network.AlphaSpaceId, "42"},
   352  	}
   353  	res, err := s.api.SpaceInfos(req)
   354  	c.Assert(err, jc.ErrorIsNil)
   355  
   356  	// Hydrate a network.SpaceInfos from the response
   357  	gotSpaceInfos := params.ToNetworkSpaceInfos(res)
   358  	c.Assert(gotSpaceInfos, gc.DeepEquals, spaceInfos[0:1], gc.Commentf("expected to get back a filtered list of the space infos"))
   359  }