github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/modelconfig/modelconfig_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package modelconfig_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	gitjujutesting "github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  	"gopkg.in/juju/names.v2"
    12  
    13  	"github.com/juju/juju/apiserver/facades/client/modelconfig"
    14  	"github.com/juju/juju/apiserver/params"
    15  	apiservertesting "github.com/juju/juju/apiserver/testing"
    16  	"github.com/juju/juju/environs/config"
    17  	"github.com/juju/juju/provider/dummy"
    18  	_ "github.com/juju/juju/provider/dummy"
    19  	"github.com/juju/juju/state"
    20  	"github.com/juju/juju/testing"
    21  )
    22  
    23  type modelconfigSuite struct {
    24  	gitjujutesting.IsolationSuite
    25  	backend    *mockBackend
    26  	authorizer apiservertesting.FakeAuthorizer
    27  	api        *modelconfig.ModelConfigAPIV2
    28  }
    29  
    30  var _ = gc.Suite(&modelconfigSuite{})
    31  
    32  func (s *modelconfigSuite) SetUpTest(c *gc.C) {
    33  	s.IsolationSuite.SetUpTest(c)
    34  	s.authorizer = apiservertesting.FakeAuthorizer{
    35  		Tag:      names.NewUserTag("bruce@local"),
    36  		AdminTag: names.NewUserTag("bruce@local"),
    37  	}
    38  	s.backend = &mockBackend{
    39  		cfg: config.ConfigValues{
    40  			"type":            {"dummy", "model"},
    41  			"agent-version":   {"1.2.3.4", "model"},
    42  			"ftp-proxy":       {"http://proxy", "model"},
    43  			"authorized-keys": {testing.FakeAuthKeys, "model"},
    44  		},
    45  	}
    46  	var err error
    47  	s.api, err = modelconfig.NewModelConfigAPI(s.backend, &s.authorizer)
    48  	c.Assert(err, jc.ErrorIsNil)
    49  }
    50  
    51  func (s *modelconfigSuite) TestModelGet(c *gc.C) {
    52  	result, err := s.api.ModelGet()
    53  	c.Assert(err, jc.ErrorIsNil)
    54  	c.Assert(result.Config, jc.DeepEquals, map[string]params.ConfigValue{
    55  		"type":          {"dummy", "model"},
    56  		"ftp-proxy":     {"http://proxy", "model"},
    57  		"agent-version": {Value: "1.2.3.4", Source: "model"},
    58  	})
    59  }
    60  
    61  func (s *modelconfigSuite) assertConfigValue(c *gc.C, key string, expected interface{}) {
    62  	value, found := s.backend.cfg[key]
    63  	c.Assert(found, jc.IsTrue)
    64  	c.Assert(value.Value, gc.Equals, expected)
    65  }
    66  
    67  func (s *modelconfigSuite) assertConfigValueMissing(c *gc.C, key string) {
    68  	_, found := s.backend.cfg[key]
    69  	c.Assert(found, jc.IsFalse)
    70  }
    71  
    72  func (s *modelconfigSuite) TestModelSet(c *gc.C) {
    73  	params := params.ModelSet{
    74  		Config: map[string]interface{}{
    75  			"some-key":  "value",
    76  			"other-key": "other value"},
    77  	}
    78  	err := s.api.ModelSet(params)
    79  	c.Assert(err, jc.ErrorIsNil)
    80  	s.assertConfigValue(c, "some-key", "value")
    81  	s.assertConfigValue(c, "other-key", "other value")
    82  }
    83  
    84  func (s *modelconfigSuite) blockAllChanges(c *gc.C, msg string) {
    85  	s.backend.msg = msg
    86  	s.backend.b = state.ChangeBlock
    87  }
    88  
    89  func (s *modelconfigSuite) assertBlocked(c *gc.C, err error, msg string) {
    90  	c.Assert(params.IsCodeOperationBlocked(err), jc.IsTrue, gc.Commentf("error: %#v", err))
    91  	c.Assert(errors.Cause(err), jc.DeepEquals, &params.Error{
    92  		Message: msg,
    93  		Code:    "operation is blocked",
    94  	})
    95  }
    96  
    97  func (s *modelconfigSuite) assertModelSetBlocked(c *gc.C, args map[string]interface{}, msg string) {
    98  	err := s.api.ModelSet(params.ModelSet{args})
    99  	s.assertBlocked(c, err, msg)
   100  }
   101  
   102  func (s *modelconfigSuite) TestBlockChangesModelSet(c *gc.C) {
   103  	s.blockAllChanges(c, "TestBlockChangesModelSet")
   104  	args := map[string]interface{}{"some-key": "value"}
   105  	s.assertModelSetBlocked(c, args, "TestBlockChangesModelSet")
   106  }
   107  
   108  func (s *modelconfigSuite) TestModelSetCannotChangeAgentVersion(c *gc.C) {
   109  	old, err := config.New(config.UseDefaults, dummy.SampleConfig().Merge(testing.Attrs{
   110  		"agent-version": "1.2.3.4",
   111  	}))
   112  	c.Assert(err, jc.ErrorIsNil)
   113  	s.backend.old = old
   114  	args := params.ModelSet{
   115  		map[string]interface{}{"agent-version": "9.9.9"},
   116  	}
   117  	err = s.api.ModelSet(args)
   118  	c.Assert(err, gc.ErrorMatches, "agent-version cannot be changed")
   119  
   120  	// It's okay to pass config back with the same agent-version.
   121  	result, err := s.api.ModelGet()
   122  	c.Assert(err, jc.ErrorIsNil)
   123  	c.Assert(result.Config["agent-version"], gc.NotNil)
   124  	args.Config["agent-version"] = result.Config["agent-version"].Value
   125  	err = s.api.ModelSet(args)
   126  	c.Assert(err, jc.ErrorIsNil)
   127  }
   128  
   129  func (s *modelconfigSuite) TestAdminCanSetLogTrace(c *gc.C) {
   130  	args := params.ModelSet{
   131  		map[string]interface{}{"logging-config": "<root>=DEBUG;somepackage=TRACE"},
   132  	}
   133  	err := s.api.ModelSet(args)
   134  	c.Assert(err, jc.ErrorIsNil)
   135  
   136  	result, err := s.api.ModelGet()
   137  	c.Assert(err, jc.ErrorIsNil)
   138  	c.Assert(result.Config["logging-config"].Value, gc.Equals, "<root>=DEBUG;somepackage=TRACE")
   139  }
   140  
   141  func (s *modelconfigSuite) TestUserCanSetLogNoTrace(c *gc.C) {
   142  	args := params.ModelSet{
   143  		map[string]interface{}{"logging-config": "<root>=DEBUG;somepackage=ERROR"},
   144  	}
   145  	apiUser := names.NewUserTag("fred")
   146  	s.authorizer.Tag = apiUser
   147  	s.authorizer.HasWriteTag = apiUser
   148  	err := s.api.ModelSet(args)
   149  	c.Assert(err, jc.ErrorIsNil)
   150  
   151  	result, err := s.api.ModelGet()
   152  	c.Assert(err, jc.ErrorIsNil)
   153  	c.Assert(result.Config["logging-config"].Value, gc.Equals, "<root>=DEBUG;somepackage=ERROR")
   154  }
   155  
   156  func (s *modelconfigSuite) TestUserReadAccess(c *gc.C) {
   157  	apiUser := names.NewUserTag("read")
   158  	s.authorizer.Tag = apiUser
   159  
   160  	_, err := s.api.ModelGet()
   161  	c.Assert(err, jc.ErrorIsNil)
   162  
   163  	err = s.api.ModelSet(params.ModelSet{})
   164  	c.Assert(errors.Cause(err), gc.ErrorMatches, "permission denied")
   165  }
   166  
   167  func (s *modelconfigSuite) TestUserCannotSetLogTrace(c *gc.C) {
   168  	args := params.ModelSet{
   169  		map[string]interface{}{"logging-config": "<root>=DEBUG;somepackage=TRACE"},
   170  	}
   171  	apiUser := names.NewUserTag("fred")
   172  	s.authorizer.Tag = apiUser
   173  	s.authorizer.HasWriteTag = apiUser
   174  	err := s.api.ModelSet(args)
   175  	c.Assert(err, gc.ErrorMatches, `only controller admins can set a model's logging level to TRACE`)
   176  }
   177  
   178  func (s *modelconfigSuite) TestModelUnset(c *gc.C) {
   179  	err := s.backend.UpdateModelConfig(map[string]interface{}{"abc": 123}, nil)
   180  	c.Assert(err, jc.ErrorIsNil)
   181  
   182  	args := params.ModelUnset{[]string{"abc"}}
   183  	err = s.api.ModelUnset(args)
   184  	c.Assert(err, jc.ErrorIsNil)
   185  	s.assertConfigValueMissing(c, "abc")
   186  }
   187  
   188  func (s *modelconfigSuite) TestBlockModelUnset(c *gc.C) {
   189  	err := s.backend.UpdateModelConfig(map[string]interface{}{"abc": 123}, nil)
   190  	c.Assert(err, jc.ErrorIsNil)
   191  	s.blockAllChanges(c, "TestBlockModelUnset")
   192  
   193  	args := params.ModelUnset{[]string{"abc"}}
   194  	err = s.api.ModelUnset(args)
   195  	s.assertBlocked(c, err, "TestBlockModelUnset")
   196  }
   197  
   198  func (s *modelconfigSuite) TestModelUnsetMissing(c *gc.C) {
   199  	// It's okay to unset a non-existent attribute.
   200  	args := params.ModelUnset{[]string{"not_there"}}
   201  	err := s.api.ModelUnset(args)
   202  	c.Assert(err, jc.ErrorIsNil)
   203  }
   204  
   205  func (s *modelconfigSuite) TestSetSupportCredentals(c *gc.C) {
   206  	err := s.api.SetSLALevel(params.ModelSLA{params.ModelSLAInfo{"level", "bob"}, []byte("foobar")})
   207  	c.Assert(err, jc.ErrorIsNil)
   208  }
   209  
   210  type mockBackend struct {
   211  	cfg config.ConfigValues
   212  	old *config.Config
   213  	b   state.BlockType
   214  	msg string
   215  }
   216  
   217  func (m *mockBackend) ModelConfigValues() (config.ConfigValues, error) {
   218  	return m.cfg, nil
   219  }
   220  
   221  func (m *mockBackend) Sequences() (map[string]int, error) {
   222  	return nil, nil
   223  }
   224  
   225  func (m *mockBackend) UpdateModelConfig(update map[string]interface{}, remove []string, validate ...state.ValidateConfigFunc) error {
   226  	for _, validateFunc := range validate {
   227  		if err := validateFunc(update, remove, m.old); err != nil {
   228  			return err
   229  		}
   230  	}
   231  	for k, v := range update {
   232  		m.cfg[k] = config.ConfigValue{v, "model"}
   233  	}
   234  	for _, n := range remove {
   235  		delete(m.cfg, n)
   236  	}
   237  	return nil
   238  }
   239  
   240  func (m *mockBackend) GetBlockForType(t state.BlockType) (state.Block, bool, error) {
   241  	if m.b == t {
   242  		return &mockBlock{t: t, m: m.msg}, true, nil
   243  	} else {
   244  		return nil, false, nil
   245  	}
   246  }
   247  
   248  func (m *mockBackend) ModelTag() names.ModelTag {
   249  	return names.NewModelTag("deadbeef-2f18-4fd2-967d-db9663db7bea")
   250  }
   251  
   252  func (m *mockBackend) ControllerTag() names.ControllerTag {
   253  	return names.NewControllerTag("deadbeef-babe-4fd2-967d-db9663db7bea")
   254  }
   255  
   256  func (m *mockBackend) SetSLA(level, owner string, credentials []byte) error {
   257  	return nil
   258  }
   259  
   260  func (m *mockBackend) SLALevel() (string, error) {
   261  	return "mock-level", nil
   262  }
   263  
   264  type mockBlock struct {
   265  	state.Block
   266  	t state.BlockType
   267  	m string
   268  }
   269  
   270  func (m mockBlock) Id() string { return "" }
   271  
   272  func (m mockBlock) Tag() (names.Tag, error) { return names.NewModelTag("mocktesting"), nil }
   273  
   274  func (m mockBlock) Type() state.BlockType { return m.t }
   275  
   276  func (m mockBlock) Message() string { return m.m }
   277  
   278  func (m mockBlock) ModelUUID() string { return "" }