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

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package caasfirewaller_test
     5  
     6  import (
     7  	"github.com/juju/charm/v12"
     8  	"github.com/juju/names/v5"
     9  	jc "github.com/juju/testing/checkers"
    10  	"github.com/juju/worker/v3/workertest"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/apiserver/common"
    14  	charmscommon "github.com/juju/juju/apiserver/common/charms"
    15  	"github.com/juju/juju/apiserver/facade"
    16  	"github.com/juju/juju/apiserver/facades/controller/caasfirewaller"
    17  	apiservertesting "github.com/juju/juju/apiserver/testing"
    18  	"github.com/juju/juju/core/life"
    19  	"github.com/juju/juju/core/network"
    20  	"github.com/juju/juju/rpc/params"
    21  	"github.com/juju/juju/state"
    22  	statetesting "github.com/juju/juju/state/testing"
    23  	coretesting "github.com/juju/juju/testing"
    24  )
    25  
    26  type firewallerBaseSuite struct {
    27  	coretesting.BaseSuite
    28  
    29  	st                  *mockState
    30  	applicationsChanges chan []string
    31  	openPortsChanges    chan []string
    32  	appExposedChanges   chan struct{}
    33  
    34  	resources  *common.Resources
    35  	authorizer *apiservertesting.FakeAuthorizer
    36  	facade     facadeCommon
    37  
    38  	newFunc func(c *gc.C, resources facade.Resources,
    39  		authorizer facade.Authorizer,
    40  		st *mockState,
    41  	) (facadeCommon, error)
    42  }
    43  
    44  type firewallerLegacySuite struct {
    45  	firewallerBaseSuite
    46  }
    47  
    48  var _ = gc.Suite(&firewallerLegacySuite{
    49  	firewallerBaseSuite: firewallerBaseSuite{
    50  		newFunc: func(c *gc.C, resources facade.Resources,
    51  			authorizer facade.Authorizer,
    52  			st *mockState,
    53  		) (facadeCommon, error) {
    54  			commonState := &mockCommonStateShim{st}
    55  			commonCharmsAPI, err := charmscommon.NewCharmInfoAPI(commonState, authorizer)
    56  			c.Assert(err, jc.ErrorIsNil)
    57  			appCharmInfoAPI, err := charmscommon.NewApplicationCharmInfoAPI(commonState, authorizer)
    58  			c.Assert(err, jc.ErrorIsNil)
    59  			return caasfirewaller.NewFacadeLegacyForTest(
    60  				resources,
    61  				authorizer,
    62  				st,
    63  				commonCharmsAPI,
    64  				appCharmInfoAPI,
    65  			)
    66  		},
    67  	},
    68  })
    69  
    70  type firewallerSidecarSuite struct {
    71  	firewallerBaseSuite
    72  
    73  	facade facadeSidecar
    74  }
    75  
    76  var _ = gc.Suite(&firewallerSidecarSuite{
    77  	firewallerBaseSuite: firewallerBaseSuite{
    78  		newFunc: func(c *gc.C, resources facade.Resources,
    79  			authorizer facade.Authorizer,
    80  			st *mockState,
    81  		) (facadeCommon, error) {
    82  			commonState := &mockCommonStateShim{st}
    83  			commonCharmsAPI, err := charmscommon.NewCharmInfoAPI(commonState, authorizer)
    84  			c.Assert(err, jc.ErrorIsNil)
    85  			appCharmInfoAPI, err := charmscommon.NewApplicationCharmInfoAPI(commonState, authorizer)
    86  			c.Assert(err, jc.ErrorIsNil)
    87  			return caasfirewaller.NewFacadeSidecarForTest(
    88  				resources,
    89  				authorizer,
    90  				st,
    91  				commonCharmsAPI,
    92  				appCharmInfoAPI,
    93  			)
    94  		},
    95  	},
    96  })
    97  
    98  func (s *firewallerSidecarSuite) SetUpTest(c *gc.C) {
    99  	s.firewallerBaseSuite.SetUpTest(c)
   100  
   101  	// charm.FormatV2.
   102  	s.st.application.charm.manifest.Bases = []charm.Base{
   103  		{
   104  			Name: "ubuntu",
   105  			Channel: charm.Channel{
   106  				Risk:  "stable",
   107  				Track: "20.04",
   108  			},
   109  		},
   110  	}
   111  
   112  	var ok bool
   113  	s.facade, ok = s.firewallerBaseSuite.facade.(facadeSidecar)
   114  	c.Assert(ok, jc.IsTrue)
   115  }
   116  
   117  func (s *firewallerSidecarSuite) TestWatchOpenedPorts(c *gc.C) {
   118  	openPortsChanges := []string{"port1", "port2"}
   119  	s.openPortsChanges <- openPortsChanges
   120  
   121  	results, err := s.facade.WatchOpenedPorts(params.Entities{
   122  		Entities: []params.Entity{{
   123  			Tag: "model-deadbeef-0bad-400d-8000-4b1d0d06f00d",
   124  		}},
   125  	})
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	result := results.Results[0]
   128  	c.Assert(result.Error, gc.IsNil)
   129  	c.Assert(result.StringsWatcherId, gc.Equals, "1")
   130  	c.Assert(result.Changes, jc.DeepEquals, openPortsChanges)
   131  }
   132  
   133  func (s *firewallerSidecarSuite) TestGetApplicationOpenedPorts(c *gc.C) {
   134  	s.st.application.appPortRanges = network.GroupedPortRanges{
   135  		"": []network.PortRange{
   136  			{
   137  				FromPort: 80,
   138  				ToPort:   80,
   139  				Protocol: "tcp",
   140  			},
   141  		},
   142  		"endport-1": []network.PortRange{
   143  			{
   144  				FromPort: 8888,
   145  				ToPort:   8888,
   146  				Protocol: "tcp",
   147  			},
   148  		},
   149  	}
   150  
   151  	results, err := s.facade.GetOpenedPorts(params.Entity{
   152  		Tag: "application-gitlab",
   153  	})
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	result := results.Results[0]
   156  	c.Assert(result.Error, gc.IsNil)
   157  	c.Assert(result.ApplicationPortRanges, gc.DeepEquals, []params.ApplicationOpenedPorts{
   158  		{
   159  			PortRanges: []params.PortRange{
   160  				{FromPort: 80, ToPort: 80, Protocol: "tcp"},
   161  			},
   162  		},
   163  		{
   164  			Endpoint: "endport-1",
   165  			PortRanges: []params.PortRange{
   166  				{FromPort: 8888, ToPort: 8888, Protocol: "tcp"},
   167  			},
   168  		},
   169  	})
   170  }
   171  
   172  type facadeCommon interface {
   173  	IsExposed(args params.Entities) (params.BoolResults, error)
   174  	ApplicationsConfig(args params.Entities) (params.ApplicationGetConfigResults, error)
   175  	WatchApplications() (params.StringsWatchResult, error)
   176  	Life(args params.Entities) (params.LifeResults, error)
   177  	Watch(args params.Entities) (params.NotifyWatchResults, error)
   178  	ApplicationCharmInfo(args params.Entity) (params.Charm, error)
   179  }
   180  
   181  type facadeSidecar interface {
   182  	facadeCommon
   183  	WatchOpenedPorts(args params.Entities) (params.StringsWatchResults, error)
   184  	GetOpenedPorts(arg params.Entity) (params.ApplicationOpenedPortsResults, error)
   185  }
   186  
   187  func (s *firewallerBaseSuite) SetUpTest(c *gc.C) {
   188  	s.BaseSuite.SetUpTest(c)
   189  
   190  	s.applicationsChanges = make(chan []string, 1)
   191  	s.appExposedChanges = make(chan struct{}, 1)
   192  	s.openPortsChanges = make(chan []string, 1)
   193  	appExposedWatcher := statetesting.NewMockNotifyWatcher(s.appExposedChanges)
   194  	s.st = &mockState{
   195  		application: mockApplication{
   196  			life:    state.Alive,
   197  			watcher: appExposedWatcher,
   198  			charm: mockCharm{
   199  				meta: &charm.Meta{
   200  					Deployment: &charm.Deployment{},
   201  				},
   202  				manifest: &charm.Manifest{},
   203  				url:      "ch:gitlab",
   204  			},
   205  		},
   206  		applicationsWatcher: statetesting.NewMockStringsWatcher(s.applicationsChanges),
   207  		openPortsWatcher:    statetesting.NewMockStringsWatcher(s.openPortsChanges),
   208  		appExposedWatcher:   appExposedWatcher,
   209  	}
   210  	s.AddCleanup(func(c *gc.C) { workertest.DirtyKill(c, s.st.applicationsWatcher) })
   211  	s.AddCleanup(func(c *gc.C) { workertest.DirtyKill(c, s.st.openPortsWatcher) })
   212  	s.AddCleanup(func(c *gc.C) { workertest.DirtyKill(c, s.st.appExposedWatcher) })
   213  
   214  	s.resources = common.NewResources()
   215  	s.authorizer = &apiservertesting.FakeAuthorizer{
   216  		Tag:        names.NewMachineTag("0"),
   217  		Controller: true,
   218  	}
   219  
   220  	facade, err := s.newFunc(c, s.resources, s.authorizer, s.st)
   221  	c.Assert(err, jc.ErrorIsNil)
   222  	s.facade = facade
   223  }
   224  
   225  func (s *firewallerBaseSuite) TestPermission(c *gc.C) {
   226  	s.authorizer = &apiservertesting.FakeAuthorizer{
   227  		Tag: names.NewMachineTag("0"),
   228  	}
   229  	_, err := s.newFunc(c, s.resources, s.authorizer, s.st)
   230  	c.Assert(err, gc.ErrorMatches, "permission denied")
   231  }
   232  
   233  func (s *firewallerBaseSuite) TestWatchApplications(c *gc.C) {
   234  	applicationNames := []string{"db2", "hadoop"}
   235  	s.applicationsChanges <- applicationNames
   236  	result, err := s.facade.WatchApplications()
   237  	c.Assert(err, jc.ErrorIsNil)
   238  	c.Assert(result.Error, gc.IsNil)
   239  	c.Assert(result.StringsWatcherId, gc.Equals, "1")
   240  	c.Assert(result.Changes, jc.DeepEquals, applicationNames)
   241  }
   242  
   243  func (s *firewallerBaseSuite) TestWatchApplication(c *gc.C) {
   244  	s.appExposedChanges <- struct{}{}
   245  
   246  	results, err := s.facade.Watch(params.Entities{
   247  		Entities: []params.Entity{
   248  			{Tag: "application-gitlab"},
   249  			{Tag: "unit-gitlab-0"},
   250  		},
   251  	})
   252  	c.Assert(err, jc.ErrorIsNil)
   253  	c.Assert(results.Results, gc.HasLen, 2)
   254  	c.Assert(results.Results[0].Error, gc.IsNil)
   255  	c.Assert(results.Results[1].Error, jc.DeepEquals, &params.Error{
   256  		Message: "permission denied",
   257  		Code:    "unauthorized access",
   258  	})
   259  
   260  	c.Assert(results.Results[0].NotifyWatcherId, gc.Equals, "1")
   261  	resource := s.resources.Get("1")
   262  	c.Assert(resource, gc.Equals, s.st.appExposedWatcher)
   263  }
   264  
   265  func (s *firewallerBaseSuite) TestIsExposed(c *gc.C) {
   266  	s.st.application.exposed = true
   267  	results, err := s.facade.IsExposed(params.Entities{
   268  		Entities: []params.Entity{
   269  			{Tag: "application-gitlab"},
   270  			{Tag: "unit-gitlab-0"},
   271  		},
   272  	})
   273  	c.Assert(err, jc.ErrorIsNil)
   274  	c.Assert(results, jc.DeepEquals, params.BoolResults{
   275  		Results: []params.BoolResult{{
   276  			Result: true,
   277  		}, {
   278  			Error: &params.Error{
   279  				Message: `"unit-gitlab-0" is not a valid application tag`,
   280  			},
   281  		}},
   282  	})
   283  }
   284  
   285  func (s *firewallerBaseSuite) TestLife(c *gc.C) {
   286  	results, err := s.facade.Life(params.Entities{
   287  		Entities: []params.Entity{
   288  			{Tag: "application-gitlab"},
   289  			{Tag: "machine-0"},
   290  		},
   291  	})
   292  	c.Assert(err, jc.ErrorIsNil)
   293  	c.Assert(results, jc.DeepEquals, params.LifeResults{
   294  		Results: []params.LifeResult{{
   295  			Life: life.Alive,
   296  		}, {
   297  			Error: &params.Error{
   298  				Code:    "unauthorized access",
   299  				Message: "permission denied",
   300  			},
   301  		}},
   302  	})
   303  }
   304  
   305  func (s *firewallerBaseSuite) TestApplicationConfig(c *gc.C) {
   306  	results, err := s.facade.ApplicationsConfig(params.Entities{
   307  		Entities: []params.Entity{
   308  			{Tag: "application-gitlab"},
   309  			{Tag: "unit-gitlab-0"},
   310  		},
   311  	})
   312  	c.Assert(err, jc.ErrorIsNil)
   313  	c.Assert(results.Results, gc.HasLen, 2)
   314  	c.Assert(results.Results[0].Error, gc.IsNil)
   315  	c.Assert(results.Results[1].Error, jc.DeepEquals, &params.Error{
   316  		Message: `"unit-gitlab-0" is not a valid application tag`,
   317  	})
   318  	c.Assert(results.Results[0].Config, jc.DeepEquals, map[string]interface{}{"foo": "bar"})
   319  }