github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/backups/restore_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package backups_test
     5  
     6  import (
     7  	"io"
     8  	"sort"
     9  
    10  	"github.com/juju/errors"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	apibackups "github.com/juju/juju/api/backups"
    15  	"github.com/juju/juju/apiserver/params"
    16  	"github.com/juju/juju/cloud"
    17  	"github.com/juju/juju/cmd/juju/backups"
    18  	"github.com/juju/juju/controller"
    19  	"github.com/juju/juju/environs"
    20  	"github.com/juju/juju/environs/bootstrap"
    21  	"github.com/juju/juju/instance"
    22  	"github.com/juju/juju/jujuclient"
    23  	"github.com/juju/juju/jujuclient/jujuclienttesting"
    24  	"github.com/juju/juju/network"
    25  	_ "github.com/juju/juju/provider/dummy"
    26  	_ "github.com/juju/juju/provider/lxd"
    27  	"github.com/juju/juju/testing"
    28  	"github.com/juju/juju/version"
    29  )
    30  
    31  type restoreSuite struct {
    32  	BaseBackupsSuite
    33  	store *jujuclienttesting.MemStore
    34  }
    35  
    36  var _ = gc.Suite(&restoreSuite{})
    37  
    38  func (s *restoreSuite) SetUpTest(c *gc.C) {
    39  	s.BaseBackupsSuite.SetUpTest(c)
    40  	clouds := map[string]cloud.Cloud{
    41  		"mycloud": {
    42  			Type:      "openstack",
    43  			AuthTypes: []cloud.AuthType{"userpass", "access-key"},
    44  			Endpoint:  "http://homestack",
    45  			Regions: []cloud.Region{
    46  				{Name: "a-region", Endpoint: "http://london/1.0"},
    47  			},
    48  		},
    49  	}
    50  	err := cloud.WritePersonalCloudMetadata(clouds)
    51  	c.Assert(err, jc.ErrorIsNil)
    52  
    53  	s.store = jujuclienttesting.NewMemStore()
    54  	s.store.Controllers["testing"] = jujuclient.ControllerDetails{
    55  		ControllerUUID:         "deadbeef-0bad-400d-8000-5b1d0d06f00d",
    56  		CACert:                 testing.CACert,
    57  		Cloud:                  "mycloud",
    58  		CloudRegion:            "a-region",
    59  		APIEndpoints:           []string{"10.0.1.1:17777"},
    60  		UnresolvedAPIEndpoints: []string{"10.0.1.1:17777"},
    61  	}
    62  	s.store.CurrentControllerName = "testing"
    63  	s.store.Models["testing"] = &jujuclient.ControllerModels{
    64  		Models: map[string]jujuclient.ModelDetails{
    65  			"admin": {"test1-uuid"},
    66  		},
    67  		CurrentModel: "admin",
    68  	}
    69  	s.store.Accounts["testing"] = jujuclient.AccountDetails{
    70  		User:     "current-user@local",
    71  		Password: "old-password",
    72  	}
    73  	s.store.BootstrapConfig["testing"] = jujuclient.BootstrapConfig{
    74  		Cloud:       "mycloud",
    75  		CloudType:   "dummy",
    76  		CloudRegion: "a-region",
    77  		Config: map[string]interface{}{
    78  			"type": "dummy",
    79  			"name": "admin",
    80  		},
    81  		ControllerModelUUID: testing.ModelTag.Id(),
    82  		ControllerConfig: controller.Config{
    83  			"api-port":   17070,
    84  			"state-port": 37017,
    85  		},
    86  	}
    87  	s.store.Credentials["dummy"] = cloud.CloudCredential{
    88  		AuthCredentials: map[string]cloud.Credential{
    89  			"me": cloud.NewCredential(cloud.UserPassAuthType, map[string]string{
    90  				"username": "user",
    91  				"password": "sekret",
    92  			}),
    93  		},
    94  	}
    95  }
    96  
    97  func (s *restoreSuite) TestRestoreArgs(c *gc.C) {
    98  	s.command = backups.NewRestoreCommandForTest(s.store, nil, nil, nil, nil)
    99  	_, err := testing.RunCommand(c, s.command, "restore")
   100  	c.Assert(err, gc.ErrorMatches, "you must specify either a file or a backup id.")
   101  
   102  	_, err = testing.RunCommand(c, s.command, "restore", "--id", "anid", "--file", "afile")
   103  	c.Assert(err, gc.ErrorMatches, "you must specify either a file or a backup id but not both.")
   104  
   105  	_, err = testing.RunCommand(c, s.command, "restore", "--id", "anid", "-b")
   106  	c.Assert(err, gc.ErrorMatches, "it is not possible to rebootstrap and restore from an id.")
   107  }
   108  
   109  // TODO(wallyworld) - add more api related unit tests
   110  type mockRestoreAPI struct {
   111  	backups.RestoreAPI
   112  }
   113  
   114  func (*mockRestoreAPI) Close() error {
   115  	return nil
   116  }
   117  
   118  func (*mockRestoreAPI) RestoreReader(io.ReadSeeker, *params.BackupsMetadataResult, apibackups.ClientConnection) error {
   119  	return nil
   120  }
   121  
   122  type mockArchiveReader struct {
   123  	backups.ArchiveReader
   124  }
   125  
   126  func (*mockArchiveReader) Close() error {
   127  	return nil
   128  }
   129  
   130  func (s *restoreSuite) TestRestoreReboostrapControllerExists(c *gc.C) {
   131  	fakeEnv := fakeEnviron{controllerInstances: []instance.Id{"1"}}
   132  	s.command = backups.NewRestoreCommandForTest(
   133  		s.store, &mockRestoreAPI{},
   134  		func(string) (backups.ArchiveReader, *params.BackupsMetadataResult, error) {
   135  			return &mockArchiveReader{}, &params.BackupsMetadataResult{}, nil
   136  		},
   137  		backups.GetEnvironFunc(fakeEnv),
   138  		backups.GetRebootstrapParamsFunc("mycloud"),
   139  	)
   140  	_, err := testing.RunCommand(c, s.command, "restore", "--file", "afile", "-b")
   141  	c.Assert(err, gc.ErrorMatches, ".*still seems to exist.*")
   142  }
   143  
   144  func (s *restoreSuite) TestRestoreReboostrapNoControllers(c *gc.C) {
   145  	fakeEnv := fakeEnviron{}
   146  	s.command = backups.NewRestoreCommandForTest(
   147  		s.store, &mockRestoreAPI{},
   148  		func(string) (backups.ArchiveReader, *params.BackupsMetadataResult, error) {
   149  			return &mockArchiveReader{}, &params.BackupsMetadataResult{
   150  				CACert: testing.CACert,
   151  			}, nil
   152  		},
   153  		backups.GetEnvironFunc(fakeEnv),
   154  		backups.GetRebootstrapParamsFunc("mycloud"),
   155  	)
   156  	s.PatchValue(&backups.BootstrapFunc, func(ctx environs.BootstrapContext, environ environs.Environ, args bootstrap.BootstrapParams) error {
   157  		return errors.New("failed to bootstrap new controller")
   158  	})
   159  
   160  	_, err := testing.RunCommand(c, s.command, "restore", "--file", "afile", "-b")
   161  	c.Assert(err, gc.ErrorMatches, ".*failed to bootstrap new controller")
   162  }
   163  
   164  func (s *restoreSuite) TestRestoreReboostrapReadsMetadata(c *gc.C) {
   165  	metadata := params.BackupsMetadataResult{
   166  		CACert:       testing.CACert,
   167  		CAPrivateKey: testing.CAKey,
   168  	}
   169  	s.command = backups.NewRestoreCommandForTest(
   170  		s.store, &mockRestoreAPI{},
   171  		func(string) (backups.ArchiveReader, *params.BackupsMetadataResult, error) {
   172  			return &mockArchiveReader{}, &metadata, nil
   173  		},
   174  		backups.GetEnvironFunc(fakeEnviron{}),
   175  		backups.GetRebootstrapParamsFunc("mycloud"),
   176  	)
   177  	s.PatchValue(&backups.BootstrapFunc, func(ctx environs.BootstrapContext, environ environs.Environ, args bootstrap.BootstrapParams) error {
   178  		return errors.New("failed to bootstrap new controller")
   179  	})
   180  
   181  	_, err := testing.RunCommand(c, s.command, "restore", "-m", "testing:test1", "--file", "afile", "-b")
   182  	c.Assert(err, gc.ErrorMatches, ".*failed to bootstrap new controller")
   183  }
   184  
   185  func (s *restoreSuite) TestFailedRestoreReboostrapMaintainsControllerInfo(c *gc.C) {
   186  	metadata := params.BackupsMetadataResult{
   187  		CACert:       testing.CACert,
   188  		CAPrivateKey: testing.CAKey,
   189  	}
   190  	s.command = backups.NewRestoreCommandForTest(
   191  		s.store, &mockRestoreAPI{},
   192  		func(string) (backups.ArchiveReader, *params.BackupsMetadataResult, error) {
   193  			return &mockArchiveReader{}, &metadata, nil
   194  		},
   195  		nil,
   196  		backups.GetRebootstrapParamsFuncWithError(),
   197  	)
   198  	s.PatchValue(&backups.BootstrapFunc, func(ctx environs.BootstrapContext, environ environs.Environ, args bootstrap.BootstrapParams) error {
   199  		// We should not call bootstrap.
   200  		c.Fail()
   201  		return nil
   202  	})
   203  
   204  	_, err := testing.RunCommand(c, s.command, "restore", "-m", "testing:test1", "--file", "afile", "-b")
   205  	c.Assert(err, gc.ErrorMatches, "failed")
   206  	// The details below are as per what was done in test setup, so no changes.
   207  	c.Assert(s.store.Controllers["testing"], jc.DeepEquals, jujuclient.ControllerDetails{
   208  		Cloud:                  "mycloud",
   209  		CloudRegion:            "a-region",
   210  		CACert:                 testing.CACert,
   211  		ControllerUUID:         "deadbeef-0bad-400d-8000-5b1d0d06f00d",
   212  		APIEndpoints:           []string{"10.0.1.1:17777"},
   213  		UnresolvedAPIEndpoints: []string{"10.0.1.1:17777"},
   214  	})
   215  }
   216  
   217  func (s *restoreSuite) TestRestoreReboostrapWritesUpdatedControllerInfo(c *gc.C) {
   218  	metadata := params.BackupsMetadataResult{
   219  		CACert:       testing.CACert,
   220  		CAPrivateKey: testing.CAKey,
   221  	}
   222  	fakeEnv := fakeEnviron{}
   223  	s.command = backups.NewRestoreCommandForTest(
   224  		s.store, &mockRestoreAPI{},
   225  		func(string) (backups.ArchiveReader, *params.BackupsMetadataResult, error) {
   226  			return &mockArchiveReader{}, &metadata, nil
   227  		},
   228  		backups.GetEnvironFunc(fakeEnv),
   229  		backups.GetRebootstrapParamsFunc("mycloud"),
   230  	)
   231  	boostrapped := false
   232  	s.PatchValue(&backups.BootstrapFunc, func(ctx environs.BootstrapContext, environ environs.Environ, args bootstrap.BootstrapParams) error {
   233  		c.Assert(args.ControllerConfig, jc.DeepEquals, controller.Config{
   234  			"controller-uuid":         "deadbeef-1bad-500d-9000-4b1d0d06f00d",
   235  			"ca-cert":                 testing.CACert,
   236  			"state-port":              1234,
   237  			"api-port":                17777,
   238  			"set-numa-control-policy": false,
   239  		})
   240  		boostrapped = true
   241  		return nil
   242  	})
   243  
   244  	intPtr := func(i int) *int {
   245  		return &i
   246  	}
   247  
   248  	_, err := testing.RunCommand(c, s.command, "restore", "-m", "testing:test1", "--file", "afile", "-b")
   249  	c.Assert(err, jc.ErrorIsNil)
   250  	c.Assert(boostrapped, jc.IsTrue)
   251  	c.Assert(s.store.Controllers["testing"], jc.DeepEquals, jujuclient.ControllerDetails{
   252  		Cloud:                  "mycloud",
   253  		CloudRegion:            "a-region",
   254  		CACert:                 testing.CACert,
   255  		ControllerUUID:         "deadbeef-1bad-500d-9000-4b1d0d06f00d",
   256  		APIEndpoints:           []string{"10.0.0.1:17777"},
   257  		UnresolvedAPIEndpoints: []string{"10.0.0.1:17777"},
   258  		AgentVersion:           version.Current.String(),
   259  		ModelCount:             intPtr(2),
   260  		MachineCount:           intPtr(1),
   261  		ControllerMachineCount: 1,
   262  	})
   263  }
   264  
   265  func (s *restoreSuite) TestRestoreReboostrapBuiltInProvider(c *gc.C) {
   266  	metadata := params.BackupsMetadataResult{
   267  		CACert:       testing.CACert,
   268  		CAPrivateKey: testing.CAKey,
   269  	}
   270  	fakeEnv := fakeEnviron{}
   271  	s.command = backups.NewRestoreCommandForTest(
   272  		s.store, &mockRestoreAPI{},
   273  		func(string) (backups.ArchiveReader, *params.BackupsMetadataResult, error) {
   274  			return &mockArchiveReader{}, &metadata, nil
   275  		},
   276  		backups.GetEnvironFunc(fakeEnv),
   277  		backups.GetRebootstrapParamsFunc("lxd"),
   278  	)
   279  	boostrapped := false
   280  	s.PatchValue(&backups.BootstrapFunc, func(ctx environs.BootstrapContext, environ environs.Environ, args bootstrap.BootstrapParams) error {
   281  		boostrapped = true
   282  		sort.Sort(args.Cloud.AuthTypes)
   283  		c.Assert(args.Cloud, jc.DeepEquals, cloud.Cloud{
   284  			Type:      "lxd",
   285  			AuthTypes: []cloud.AuthType{"empty"},
   286  			Regions:   []cloud.Region{{Name: "localhost"}},
   287  		})
   288  		return nil
   289  	})
   290  
   291  	_, err := testing.RunCommand(c, s.command, "restore", "-m", "testing:test1", "--file", "afile", "-b")
   292  	c.Assert(err, jc.ErrorIsNil)
   293  	c.Assert(boostrapped, jc.IsTrue)
   294  }
   295  
   296  type fakeInstance struct {
   297  	instance.Instance
   298  	id instance.Id
   299  }
   300  
   301  func (f fakeInstance) Addresses() ([]network.Address, error) {
   302  	return []network.Address{
   303  		{Value: "10.0.0.1"},
   304  	}, nil
   305  }
   306  
   307  type fakeEnviron struct {
   308  	environs.Environ
   309  	controllerInstances []instance.Id
   310  }
   311  
   312  func (f fakeEnviron) ControllerInstances(_ string) ([]instance.Id, error) {
   313  	return f.controllerInstances, nil
   314  }
   315  
   316  func (f fakeEnviron) Instances(ids []instance.Id) ([]instance.Instance, error) {
   317  	return []instance.Instance{fakeInstance{id: "1"}}, nil
   318  }
   319  
   320  func (f fakeEnviron) AllInstances() ([]instance.Instance, error) {
   321  	return []instance.Instance{fakeInstance{id: "1"}}, nil
   322  }